Supports the separate display for the input window.

Bug: 136039906
Test: Test manually with the uncommented example config in hawk_md.
Change-Id: I404cc2ce137563ced8e2180dd0539bd98524ff57
This commit is contained in:
Yuncheol Heo
2019-07-09 09:43:20 -07:00
parent 36ad40ad96
commit 073cb3db84
2 changed files with 82 additions and 2 deletions

View File

@@ -0,0 +1,35 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
/*
** Copyright 2019, The Android Open Source Project
**
** Licensed under the Apache License, Version 2.0 (the "License");
** you may not use this file except in compliance with the License.
** You may obtain a copy of the License at
**
** http://www.apache.org/licenses/LICENSE-2.0
**
** Unless required by applicable law or agreed to in writing, software
** distributed under the License is distributed on an "AS IS" BASIS,
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
** See the License for the specific language governing permissions and
** limitations under the License.
*/
-->
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string-array name="config_inputDisplayToImeDisplay">
<!--
The MultiClientInputMethod will use the same display for the IME window by default.
But, if you want to use the separate display for the IME window, consider to define item of
'config_inputDisplayToImeDisplay'. The each item is a comma-separated pair of the uniqueId of
the displays. The first is the uniqueId of the display where the input happens and the second
is the unqiueId of the display where the IME window will be shown.
FYI, you can find the uniqueId of displays in "dumpsys display".
E.g. If you have two displays 19261083906282752, local:19260422155234049 and you want to use
local:19260422155234049 as the IME window for the input at the display local:19261083906282752,
then the config item will be:
<item>local:19261083906282752,local:19260422155234049</item>
-->
</string-array>
</resources>

View File

@@ -16,7 +16,9 @@
package com.example.android.multiclientinputmethod; package com.example.android.multiclientinputmethod;
import android.annotation.NonNull;
import android.app.Service; import android.app.Service;
import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.hardware.display.DisplayManager; import android.hardware.display.DisplayManager;
import android.hardware.display.DisplayManager.DisplayListener; import android.hardware.display.DisplayManager.DisplayListener;
@@ -24,6 +26,7 @@ import android.inputmethodservice.MultiClientInputMethodServiceDelegate;
import android.os.IBinder; import android.os.IBinder;
import android.util.Log; import android.util.Log;
import android.util.SparseIntArray; import android.util.SparseIntArray;
import android.view.Display;
/** /**
* A {@link Service} that implements multi-client IME protocol. * A {@link Service} that implements multi-client IME protocol.
@@ -34,6 +37,9 @@ public final class MultiClientInputMethod extends Service implements DisplayList
// last client that had active InputConnection for a given displayId. // last client that had active InputConnection for a given displayId.
final SparseIntArray mDisplayToLastClientId = new SparseIntArray(); final SparseIntArray mDisplayToLastClientId = new SparseIntArray();
// Mapping table from the display where IME is attached to the display where IME window will be
// shown. Assumes that missing display will use the same display for the IME window.
SparseIntArray mInputDisplayToImeDisplay;
SoftInputWindowManager mSoftInputWindowManager; SoftInputWindowManager mSoftInputWindowManager;
MultiClientInputMethodServiceDelegate mDelegate; MultiClientInputMethodServiceDelegate mDelegate;
@@ -44,6 +50,7 @@ public final class MultiClientInputMethod extends Service implements DisplayList
if (DEBUG) { if (DEBUG) {
Log.v(TAG, "onCreate"); Log.v(TAG, "onCreate");
} }
mInputDisplayToImeDisplay = buildInputDisplayToImeDisplay();
mDelegate = MultiClientInputMethodServiceDelegate.create(this, mDelegate = MultiClientInputMethodServiceDelegate.create(this,
new MultiClientInputMethodServiceDelegate.ServiceCallback() { new MultiClientInputMethodServiceDelegate.ServiceCallback() {
@Override @Override
@@ -56,13 +63,17 @@ public final class MultiClientInputMethod extends Service implements DisplayList
@Override @Override
public void addClient(int clientId, int uid, int pid, public void addClient(int clientId, int uid, int pid,
int selfReportedDisplayId) { int selfReportedDisplayId) {
int imeDisplayId = mInputDisplayToImeDisplay.get(selfReportedDisplayId,
selfReportedDisplayId);
final ClientCallbackImpl callback = new ClientCallbackImpl( final ClientCallbackImpl callback = new ClientCallbackImpl(
MultiClientInputMethod.this, mDelegate, MultiClientInputMethod.this, mDelegate,
mSoftInputWindowManager, clientId, uid, pid, selfReportedDisplayId); mSoftInputWindowManager, clientId, uid, pid, imeDisplayId);
if (DEBUG) { if (DEBUG) {
Log.v(TAG, "addClient clientId=" + clientId + " uid=" + uid Log.v(TAG, "addClient clientId=" + clientId + " uid=" + uid
+ " pid=" + pid + " displayId=" + selfReportedDisplayId); + " pid=" + pid + " displayId=" + selfReportedDisplayId
+ " imeDisplayId=" + imeDisplayId);
} }
mDelegate.acceptClient(clientId, callback, callback.getDispatcherState(), mDelegate.acceptClient(clientId, callback, callback.getDispatcherState(),
callback.getLooper()); callback.getLooper());
} }
@@ -118,4 +129,38 @@ public final class MultiClientInputMethod extends Service implements DisplayList
} }
mDelegate.onDestroy(); mDelegate.onDestroy();
} }
@NonNull
private SparseIntArray buildInputDisplayToImeDisplay() {
// TODO: Support the virtual display after b/137375833 is fixed.
Context context = getApplicationContext();
String config[] = context.getResources().getStringArray(
R.array.config_inputDisplayToImeDisplay);
SparseIntArray inputDisplayToImeDisplay = new SparseIntArray();
Display[] displays = context.getSystemService(DisplayManager.class).getDisplays();
for (String item: config) {
String[] pair = item.split(",");
if (pair.length != 2) {
Log.w(TAG, "Skip illegal config: " + item);
continue;
}
int inputDisplay = findDisplayId(displays, pair[0]);
int imeDisplay = findDisplayId(displays, pair[1]);
if (inputDisplay != Display.INVALID_DISPLAY && imeDisplay != Display.INVALID_DISPLAY) {
inputDisplayToImeDisplay.put(inputDisplay, imeDisplay);
}
}
return inputDisplayToImeDisplay;
}
private static int findDisplayId(Display displays[], String uniqueId) {
for (Display display: displays) {
if (uniqueId.equals(display.getUniqueId())) {
return display.getDisplayId();
}
}
Log.w(TAG, "Can't find the display of " + uniqueId);
return Display.INVALID_DISPLAY;
}
} }