summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/java/android/view/inputmethod/InputMethodManager.java3
-rw-r--r--core/java/com/android/internal/inputmethod/InputMethodDebug.java2
-rw-r--r--core/java/com/android/internal/inputmethod/SoftInputShowHideReason.java16
-rw-r--r--core/java/com/android/internal/inputmethod/StartInputFlags.java6
-rw-r--r--packages/SettingsLib/res/values-ko/strings.xml2
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/MediaDeviceManager.kt35
-rw-r--r--packages/SystemUI/src/com/android/systemui/wm/DisplayImeController.java50
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/media/MediaDeviceManagerTest.kt74
-rw-r--r--services/core/java/com/android/server/inputmethod/InputMethodManagerService.java55
-rw-r--r--services/core/java/com/android/server/wm/WindowManagerService.java2
10 files changed, 187 insertions, 58 deletions
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
index 0d21673dfc71..5f8b13b5b548 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -611,7 +611,8 @@ public final class InputMethodManager {
@Override
public void startInputAsyncOnWindowFocusGain(View focusedView,
@SoftInputModeFlags int softInputMode, int windowFlags, boolean forceNewFocus) {
- final int startInputFlags = getStartInputFlags(focusedView, 0);
+ int startInputFlags = getStartInputFlags(focusedView, 0);
+ startInputFlags |= StartInputFlags.WINDOW_GAINED_FOCUS;
final ImeFocusController controller = getFocusController();
if (controller == null) {
diff --git a/core/java/com/android/internal/inputmethod/InputMethodDebug.java b/core/java/com/android/internal/inputmethod/InputMethodDebug.java
index 37f68233db53..3bcba75ec163 100644
--- a/core/java/com/android/internal/inputmethod/InputMethodDebug.java
+++ b/core/java/com/android/internal/inputmethod/InputMethodDebug.java
@@ -224,6 +224,8 @@ public final class InputMethodDebug {
return "HIDE_DOCKED_STACK_ATTACHED";
case SoftInputShowHideReason.HIDE_RECENTS_ANIMATION:
return "HIDE_RECENTS_ANIMATION";
+ case SoftInputShowHideReason.HIDE_SAME_WINDOW_FOCUSED_WITHOUT_EDITOR:
+ return "HIDE_SAME_WINDOW_FOCUSED_WITHOUT_EDITOR";
default:
return "Unknown=" + reason;
}
diff --git a/core/java/com/android/internal/inputmethod/SoftInputShowHideReason.java b/core/java/com/android/internal/inputmethod/SoftInputShowHideReason.java
index 4b968b45f122..f46626be48a8 100644
--- a/core/java/com/android/internal/inputmethod/SoftInputShowHideReason.java
+++ b/core/java/com/android/internal/inputmethod/SoftInputShowHideReason.java
@@ -47,7 +47,8 @@ import java.lang.annotation.Retention;
SoftInputShowHideReason.HIDE_POWER_BUTTON_GO_HOME,
SoftInputShowHideReason.HIDE_DOCKED_STACK_ATTACHED,
SoftInputShowHideReason.HIDE_RECENTS_ANIMATION,
- SoftInputShowHideReason.HIDE_BUBBLES})
+ SoftInputShowHideReason.HIDE_BUBBLES,
+ SoftInputShowHideReason.HIDE_SAME_WINDOW_FOCUSED_WITHOUT_EDITOR})
public @interface SoftInputShowHideReason {
/** Show soft input by {@link android.view.inputmethod.InputMethodManager#showSoftInput}. */
int SHOW_SOFT_INPUT = 0;
@@ -147,4 +148,17 @@ public @interface SoftInputShowHideReason {
* switching, or collapsing Bubbles.
*/
int HIDE_BUBBLES = 19;
+
+ /**
+ * Hide soft input when focusing the same window (e.g. screen turned-off and turn-on) which no
+ * valid focused editor.
+ *
+ * Note: From Android R, the window focus change callback is processed by InputDispatcher,
+ * some focus behavior changes (e.g. There are an activity with a dialog window, after
+ * screen turned-off and turned-on, before Android R the window focus sequence would be
+ * the activity first and then the dialog focused, however, in R the focus sequence would be
+ * only the dialog focused as it's the latest window with input focus) makes we need to hide
+ * soft-input when the same window focused again to align with the same behavior prior to R.
+ */
+ int HIDE_SAME_WINDOW_FOCUSED_WITHOUT_EDITOR = 20;
}
diff --git a/core/java/com/android/internal/inputmethod/StartInputFlags.java b/core/java/com/android/internal/inputmethod/StartInputFlags.java
index 5a8d2c227256..ac83987ef12c 100644
--- a/core/java/com/android/internal/inputmethod/StartInputFlags.java
+++ b/core/java/com/android/internal/inputmethod/StartInputFlags.java
@@ -47,4 +47,10 @@ public @interface StartInputFlags {
* documented hence we probably need to revisit this though.
*/
int INITIAL_CONNECTION = 4;
+
+ /**
+ * The start input happens when the window gained focus to call
+ * {@code android.view.inputmethod.InputMethodManager#startInputAsyncOnWindowFocusGain}.
+ */
+ int WINDOW_GAINED_FOCUS = 8;
}
diff --git a/packages/SettingsLib/res/values-ko/strings.xml b/packages/SettingsLib/res/values-ko/strings.xml
index 696ed2955daa..f13d9b860dce 100644
--- a/packages/SettingsLib/res/values-ko/strings.xml
+++ b/packages/SettingsLib/res/values-ko/strings.xml
@@ -538,7 +538,7 @@
<string name="user_setup_button_setup_now" msgid="1708269547187760639">"지금 설정"</string>
<string name="user_setup_button_setup_later" msgid="8712980133555493516">"나중에"</string>
<string name="user_add_user_type_title" msgid="551279664052914497">"추가"</string>
- <string name="user_new_user_name" msgid="60979820612818840">"새 사용자"</string>
+ <string name="user_new_user_name" msgid="60979820612818840">"신규 사용자"</string>
<string name="user_new_profile_name" msgid="2405500423304678841">"새 프로필"</string>
<string name="user_info_settings_title" msgid="6351390762733279907">"사용자 정보"</string>
<string name="profile_info_settings_title" msgid="105699672534365099">"프로필 정보"</string>
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaDeviceManager.kt b/packages/SystemUI/src/com/android/systemui/media/MediaDeviceManager.kt
index 102a4842e3c3..a993d00df01e 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaDeviceManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaDeviceManager.kt
@@ -16,7 +16,6 @@
package com.android.systemui.media
-import android.content.Context
import android.media.MediaRouter2Manager
import android.media.session.MediaController
import androidx.annotation.AnyThread
@@ -24,20 +23,22 @@ import androidx.annotation.MainThread
import androidx.annotation.WorkerThread
import com.android.settingslib.media.LocalMediaManager
import com.android.settingslib.media.MediaDevice
+import com.android.systemui.Dumpable
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.dagger.qualifiers.Main
-import com.android.systemui.Dumpable
import com.android.systemui.dump.DumpManager
import java.io.FileDescriptor
import java.io.PrintWriter
import java.util.concurrent.Executor
import javax.inject.Inject
+private const val PLAYBACK_TYPE_UNKNOWN = 0
+
/**
* Provides information about the route (ie. device) where playback is occurring.
*/
class MediaDeviceManager @Inject constructor(
- private val context: Context,
+ private val controllerFactory: MediaControllerFactory,
private val localMediaManagerFactory: LocalMediaManagerFactory,
private val mr2manager: MediaRouter2Manager,
@Main private val fgExecutor: Executor,
@@ -71,7 +72,7 @@ class MediaDeviceManager @Inject constructor(
if (entry == null || entry?.token != data.token) {
entry?.stop()
val controller = data.token?.let {
- MediaController(context, it)
+ controllerFactory.create(it)
}
entry = Entry(key, oldKey, controller,
localMediaManagerFactory.create(data.packageName))
@@ -122,11 +123,12 @@ class MediaDeviceManager @Inject constructor(
val oldKey: String?,
val controller: MediaController?,
val localMediaManager: LocalMediaManager
- ) : LocalMediaManager.DeviceCallback {
+ ) : LocalMediaManager.DeviceCallback, MediaController.Callback() {
val token
get() = controller?.sessionToken
private var started = false
+ private var playbackType = PLAYBACK_TYPE_UNKNOWN
private var current: MediaDevice? = null
set(value) {
if (!started || value != field) {
@@ -141,6 +143,8 @@ class MediaDeviceManager @Inject constructor(
fun start() = bgExecutor.execute {
localMediaManager.registerCallback(this)
localMediaManager.startScan()
+ playbackType = controller?.playbackInfo?.playbackType ?: PLAYBACK_TYPE_UNKNOWN
+ controller?.registerCallback(this)
updateCurrent()
started = true
}
@@ -148,22 +152,37 @@ class MediaDeviceManager @Inject constructor(
@AnyThread
fun stop() = bgExecutor.execute {
started = false
+ controller?.unregisterCallback(this)
localMediaManager.stopScan()
localMediaManager.unregisterCallback(this)
}
fun dump(fd: FileDescriptor, pw: PrintWriter, args: Array<String>) {
- val route = controller?.let {
+ val routingSession = controller?.let {
mr2manager.getRoutingSessionForMediaController(it)
}
+ val selectedRoutes = routingSession?.let {
+ mr2manager.getSelectedRoutes(it)
+ }
with(pw) {
println(" current device is ${current?.name}")
val type = controller?.playbackInfo?.playbackType
- println(" PlaybackType=$type (1 for local, 2 for remote)")
- println(" route=$route")
+ println(" PlaybackType=$type (1 for local, 2 for remote) cached=$playbackType")
+ println(" routingSession=$routingSession")
+ println(" selectedRoutes=$selectedRoutes")
}
}
+ @WorkerThread
+ override fun onAudioInfoChanged(info: MediaController.PlaybackInfo?) {
+ val newPlaybackType = info?.playbackType ?: PLAYBACK_TYPE_UNKNOWN
+ if (newPlaybackType == playbackType) {
+ return
+ }
+ playbackType = newPlaybackType
+ updateCurrent()
+ }
+
override fun onDeviceListUpdate(devices: List<MediaDevice>?) = bgExecutor.execute {
updateCurrent()
}
diff --git a/packages/SystemUI/src/com/android/systemui/wm/DisplayImeController.java b/packages/SystemUI/src/com/android/systemui/wm/DisplayImeController.java
index 89f469a438a9..dd4ea578dafe 100644
--- a/packages/SystemUI/src/com/android/systemui/wm/DisplayImeController.java
+++ b/packages/SystemUI/src/com/android/systemui/wm/DisplayImeController.java
@@ -228,12 +228,22 @@ public class DisplayImeController implements DisplayController.OnDisplaysChanged
mHandler.post(() -> {
final Point lastSurfacePosition = mImeSourceControl != null
? mImeSourceControl.getSurfacePosition() : null;
+ final boolean positionChanged =
+ !activeControl.getSurfacePosition().equals(lastSurfacePosition);
+ final boolean leashChanged =
+ !haveSameLeash(mImeSourceControl, activeControl);
mImeSourceControl = activeControl;
- if (!activeControl.getSurfacePosition().equals(lastSurfacePosition)
- && mAnimation != null) {
- startAnimation(mImeShowing, true /* forceRestart */);
- } else if (!mImeShowing) {
- removeImeSurface();
+ if (mAnimation != null) {
+ if (positionChanged) {
+ startAnimation(mImeShowing, true /* forceRestart */);
+ }
+ } else {
+ if (leashChanged) {
+ applyVisibilityToLeash();
+ }
+ if (!mImeShowing) {
+ removeImeSurface();
+ }
}
});
}
@@ -241,6 +251,20 @@ public class DisplayImeController implements DisplayController.OnDisplaysChanged
}
}
+ private void applyVisibilityToLeash() {
+ SurfaceControl leash = mImeSourceControl.getLeash();
+ if (leash != null) {
+ SurfaceControl.Transaction t = mTransactionPool.acquire();
+ if (mImeShowing) {
+ t.show(leash);
+ } else {
+ t.hide(leash);
+ }
+ t.apply();
+ mTransactionPool.release(t);
+ }
+ }
+
@Override
public void showInsets(int types, boolean fromIme) {
if ((types & WindowInsets.Type.ime()) == 0) {
@@ -492,4 +516,20 @@ public class DisplayImeController implements DisplayController.OnDisplaysChanged
return IInputMethodManager.Stub.asInterface(
ServiceManager.getService(Context.INPUT_METHOD_SERVICE));
}
+
+ private static boolean haveSameLeash(InsetsSourceControl a, InsetsSourceControl b) {
+ if (a == b) {
+ return true;
+ }
+ if (a == null || b == null) {
+ return false;
+ }
+ if (a.getLeash() == b.getLeash()) {
+ return true;
+ }
+ if (a.getLeash() == null || b.getLeash() == null) {
+ return false;
+ }
+ return a.getLeash().isSameSurface(b.getLeash());
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/MediaDeviceManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/MediaDeviceManagerTest.kt
index fdb432cc097c..ab3b20898b23 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/MediaDeviceManagerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaDeviceManagerTest.kt
@@ -16,13 +16,12 @@
package com.android.systemui.media
-import android.app.Notification
import android.graphics.drawable.Drawable
-import android.media.MediaMetadata
import android.media.MediaRouter2Manager
import android.media.RoutingSessionInfo
+import android.media.session.MediaController
+import android.media.session.MediaController.PlaybackInfo
import android.media.session.MediaSession
-import android.media.session.PlaybackState
import android.testing.AndroidTestingRunner
import android.testing.TestableLooper
import androidx.test.filters.SmallTest
@@ -55,7 +54,6 @@ private const val KEY = "TEST_KEY"
private const val KEY_OLD = "TEST_KEY_OLD"
private const val PACKAGE = "PKG"
private const val SESSION_KEY = "SESSION_KEY"
-private const val SESSION_ARTIST = "SESSION_ARTIST"
private const val SESSION_TITLE = "SESSION_TITLE"
private const val DEVICE_NAME = "DEVICE_NAME"
private const val USER_ID = 0
@@ -68,6 +66,7 @@ private fun <T> eq(value: T): T = Mockito.eq(value) ?: value
public class MediaDeviceManagerTest : SysuiTestCase() {
private lateinit var manager: MediaDeviceManager
+ @Mock private lateinit var controllerFactory: MediaControllerFactory
@Mock private lateinit var lmmFactory: LocalMediaManagerFactory
@Mock private lateinit var lmm: LocalMediaManager
@Mock private lateinit var mr2: MediaRouter2Manager
@@ -78,10 +77,9 @@ public class MediaDeviceManagerTest : SysuiTestCase() {
@Mock private lateinit var device: MediaDevice
@Mock private lateinit var icon: Drawable
@Mock private lateinit var route: RoutingSessionInfo
+ @Mock private lateinit var controller: MediaController
+ @Mock private lateinit var playbackInfo: PlaybackInfo
private lateinit var session: MediaSession
- private lateinit var metadataBuilder: MediaMetadata.Builder
- private lateinit var playbackBuilder: PlaybackState.Builder
- private lateinit var notifBuilder: Notification.Builder
private lateinit var mediaData: MediaData
@JvmField @Rule val mockito = MockitoJUnit.rule()
@@ -89,8 +87,8 @@ public class MediaDeviceManagerTest : SysuiTestCase() {
fun setUp() {
fakeFgExecutor = FakeExecutor(FakeSystemClock())
fakeBgExecutor = FakeExecutor(FakeSystemClock())
- manager = MediaDeviceManager(context, lmmFactory, mr2, fakeFgExecutor, fakeBgExecutor,
- dumpster)
+ manager = MediaDeviceManager(controllerFactory, lmmFactory, mr2, fakeFgExecutor,
+ fakeBgExecutor, dumpster)
manager.addListener(listener)
// Configure mocks.
@@ -101,28 +99,13 @@ public class MediaDeviceManagerTest : SysuiTestCase() {
whenever(mr2.getRoutingSessionForMediaController(any())).thenReturn(route)
// Create a media sesssion and notification for testing.
- metadataBuilder = MediaMetadata.Builder().apply {
- putString(MediaMetadata.METADATA_KEY_ARTIST, SESSION_ARTIST)
- putString(MediaMetadata.METADATA_KEY_TITLE, SESSION_TITLE)
- }
- playbackBuilder = PlaybackState.Builder().apply {
- setState(PlaybackState.STATE_PAUSED, 6000L, 1f)
- setActions(PlaybackState.ACTION_PLAY)
- }
- session = MediaSession(context, SESSION_KEY).apply {
- setMetadata(metadataBuilder.build())
- setPlaybackState(playbackBuilder.build())
- }
- session.setActive(true)
- notifBuilder = Notification.Builder(context, "NONE").apply {
- setContentTitle(SESSION_TITLE)
- setContentText(SESSION_ARTIST)
- setSmallIcon(android.R.drawable.ic_media_pause)
- setStyle(Notification.MediaStyle().setMediaSession(session.getSessionToken()))
- }
+ session = MediaSession(context, SESSION_KEY)
+
mediaData = MediaData(USER_ID, true, 0, PACKAGE, null, null, SESSION_TITLE, null,
emptyList(), emptyList(), PACKAGE, session.sessionToken, clickIntent = null,
device = null, active = true, resumeAction = null)
+ whenever(controllerFactory.create(session.sessionToken))
+ .thenReturn(controller)
}
@After
@@ -336,6 +319,41 @@ public class MediaDeviceManagerTest : SysuiTestCase() {
assertThat(data.icon).isNull()
}
+ @Test
+ fun audioInfoChanged() {
+ whenever(playbackInfo.getPlaybackType()).thenReturn(PlaybackInfo.PLAYBACK_TYPE_LOCAL)
+ whenever(controller.getPlaybackInfo()).thenReturn(playbackInfo)
+ // GIVEN a controller with local playback type
+ manager.onMediaDataLoaded(KEY, null, mediaData)
+ fakeBgExecutor.runAllReady()
+ fakeFgExecutor.runAllReady()
+ reset(mr2)
+ // WHEN onAudioInfoChanged fires with remote playback type
+ whenever(playbackInfo.getPlaybackType()).thenReturn(PlaybackInfo.PLAYBACK_TYPE_REMOTE)
+ val captor = ArgumentCaptor.forClass(MediaController.Callback::class.java)
+ verify(controller).registerCallback(captor.capture())
+ captor.value.onAudioInfoChanged(playbackInfo)
+ // THEN the route is checked
+ verify(mr2).getRoutingSessionForMediaController(eq(controller))
+ }
+
+ @Test
+ fun audioInfoHasntChanged() {
+ whenever(playbackInfo.getPlaybackType()).thenReturn(PlaybackInfo.PLAYBACK_TYPE_REMOTE)
+ whenever(controller.getPlaybackInfo()).thenReturn(playbackInfo)
+ // GIVEN a controller with remote playback type
+ manager.onMediaDataLoaded(KEY, null, mediaData)
+ fakeBgExecutor.runAllReady()
+ fakeFgExecutor.runAllReady()
+ reset(mr2)
+ // WHEN onAudioInfoChanged fires with remote playback type
+ val captor = ArgumentCaptor.forClass(MediaController.Callback::class.java)
+ verify(controller).registerCallback(captor.capture())
+ captor.value.onAudioInfoChanged(playbackInfo)
+ // THEN the route is not checked
+ verify(mr2, never()).getRoutingSessionForMediaController(eq(controller))
+ }
+
fun captureCallback(): LocalMediaManager.DeviceCallback {
val captor = ArgumentCaptor.forClass(LocalMediaManager.DeviceCallback::class.java)
verify(lmm).registerCallback(captor.capture())
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index 7cce78bb661d..bcfbcd124e71 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -3275,6 +3275,9 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
boolean hideCurrentInputLocked(IBinder windowToken, int flags, ResultReceiver resultReceiver,
@SoftInputShowHideReason int reason) {
+ if (mCurClient == null || mCurClient.curSession == null) {
+ return false;
+ }
if ((flags&InputMethodManager.HIDE_IMPLICIT_ONLY) != 0
&& (mShowExplicitlyRequested || mShowForced)) {
if (DEBUG) Slog.v(TAG, "Not hiding: explicit show not cancelled by non-explicit hide");
@@ -3459,7 +3462,12 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
// pre-rendering not supported on low-ram devices.
cs.shouldPreRenderIme = DebugFlags.FLAG_PRE_RENDER_IME_VIEWS.value() && !mIsLowRam;
- if (mCurFocusedWindow == windowToken) {
+ final boolean sameWindowFocused = mCurFocusedWindow == windowToken;
+ final boolean isTextEditor = (startInputFlags & StartInputFlags.IS_TEXT_EDITOR) != 0;
+ final boolean startInputByWinGainedFocus =
+ (startInputFlags & StartInputFlags.WINDOW_GAINED_FOCUS) != 0;
+
+ if (sameWindowFocused && isTextEditor) {
if (DEBUG) {
Slog.w(TAG, "Window already focused, ignoring focus gain of: " + client
+ " attribute=" + attribute + ", token = " + windowToken
@@ -3474,6 +3482,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
InputBindResult.ResultCode.SUCCESS_REPORT_WINDOW_FOCUS_ONLY,
null, null, null, -1, null);
}
+
mCurFocusedWindow = windowToken;
mCurFocusedWindowSoftInputMode = softInputMode;
mCurFocusedWindowClient = cs;
@@ -3491,7 +3500,6 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
== LayoutParams.SOFT_INPUT_ADJUST_RESIZE
|| mRes.getConfiguration().isLayoutSizeAtLeast(
Configuration.SCREENLAYOUT_SIZE_LARGE);
- final boolean isTextEditor = (startInputFlags & StartInputFlags.IS_TEXT_EDITOR) != 0;
// We want to start input before showing the IME, but after closing
// it. We want to do this after closing it to help the IME disappear
@@ -3502,7 +3510,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
InputBindResult res = null;
switch (softInputMode & LayoutParams.SOFT_INPUT_MASK_STATE) {
case LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED:
- if (!isTextEditor || !doAutoShow) {
+ if (!sameWindowFocused && (!isTextEditor || !doAutoShow)) {
if (LayoutParams.mayUseInputMethod(windowFlags)) {
// There is no focus view, and this window will
// be behind any soft input window, so hide the
@@ -3551,9 +3559,11 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
}
break;
case LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN:
- if (DEBUG) Slog.v(TAG, "Window asks to hide input");
- hideCurrentInputLocked(mCurFocusedWindow, 0, null,
- SoftInputShowHideReason.HIDE_ALWAYS_HIDDEN_STATE);
+ if (!sameWindowFocused) {
+ if (DEBUG) Slog.v(TAG, "Window asks to hide input");
+ hideCurrentInputLocked(mCurFocusedWindow, 0, null,
+ SoftInputShowHideReason.HIDE_ALWAYS_HIDDEN_STATE);
+ }
break;
case LayoutParams.SOFT_INPUT_STATE_VISIBLE:
if ((softInputMode & LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION) != 0) {
@@ -3578,13 +3588,15 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
if (DEBUG) Slog.v(TAG, "Window asks to always show input");
if (InputMethodUtils.isSoftInputModeStateVisibleAllowed(
unverifiedTargetSdkVersion, startInputFlags)) {
- if (attribute != null) {
- res = startInputUncheckedLocked(cs, inputContext, missingMethods,
- attribute, startInputFlags, startInputReason);
- didStart = true;
+ if (!sameWindowFocused) {
+ if (attribute != null) {
+ res = startInputUncheckedLocked(cs, inputContext, missingMethods,
+ attribute, startInputFlags, startInputReason);
+ didStart = true;
+ }
+ showCurrentInputLocked(windowToken, InputMethodManager.SHOW_IMPLICIT, null,
+ SoftInputShowHideReason.SHOW_STATE_ALWAYS_VISIBLE);
}
- showCurrentInputLocked(windowToken, InputMethodManager.SHOW_IMPLICIT, null,
- SoftInputShowHideReason.SHOW_STATE_ALWAYS_VISIBLE);
} else {
Slog.e(TAG, "SOFT_INPUT_STATE_ALWAYS_VISIBLE is ignored because"
+ " there is no focused view that also returns true from"
@@ -3595,7 +3607,20 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
if (!didStart) {
if (attribute != null) {
- if (!DebugFlags.FLAG_OPTIMIZE_START_INPUT.value()
+ if (sameWindowFocused) {
+ // On previous platforms, when Dialogs re-gained focus, the Activity behind
+ // would briefly gain focus first, and dismiss the IME.
+ // On R that behavior has been fixed, but unfortunately apps have come
+ // to rely on this behavior to hide the IME when the editor no longer has focus
+ // To maintain compatibility, we are now hiding the IME when we don't have
+ // an editor upon refocusing a window.
+ if (startInputByWinGainedFocus) {
+ hideCurrentInputLocked(mCurFocusedWindow, 0, null,
+ SoftInputShowHideReason.HIDE_SAME_WINDOW_FOCUSED_WITHOUT_EDITOR);
+ }
+ res = startInputUncheckedLocked(cs, inputContext, missingMethods, attribute,
+ startInputFlags, startInputReason);
+ } else if (!DebugFlags.FLAG_OPTIMIZE_START_INPUT.value()
|| (startInputFlags & StartInputFlags.IS_TEXT_EDITOR) != 0) {
res = startInputUncheckedLocked(cs, inputContext, missingMethods, attribute,
startInputFlags, startInputReason);
@@ -3609,6 +3634,10 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
return res;
}
+ private boolean isImeVisible() {
+ return (mImeWindowVis & InputMethodService.IME_VISIBLE) != 0;
+ }
+
private boolean canShowInputMethodPickerLocked(IInputMethodClient client) {
// TODO(yukawa): multi-display support.
final int uid = Binder.getCallingUid();
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 03834c348d4b..b7a2eb3c705d 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -6187,7 +6187,7 @@ public class WindowManagerService extends IWindowManager.Stub
}
if (inputMethodControlTarget != null) {
pw.print(" inputMethodControlTarget in display# "); pw.print(displayId);
- pw.print(' '); pw.println(inputMethodControlTarget.getWindow());
+ pw.print(' '); pw.println(inputMethodControlTarget);
}
});
pw.print(" mInTouchMode="); pw.println(mInTouchMode);