Background
A custom editor view in Android is able to receive text from a system keyboard though an InputConnection
. I have been able to make such a view successfully. However, when the device is in landscape mode, the system will sometimes choose to show a extracted text view. When users type in this mode the extracted text view should be updated with the same text that is in the custom view.
I have not been able to implement the extracted text view functionality. (Here are some things I've tried.)
I also have not been able to find any clear documentation or full examples of how to do it. (Here are some of the better things I've read: one, two, three, four).
MCVE
I've created the most basic custom editor that I can. The following gif shows the functionality. It can receive text from the keyboard but it does not update the extracted text view in landscape orientation. Thus you can't see the updated text unless you dismiss the keyboard.
MyCustomView.java
public class MyCustomView extends View {
SpannableStringBuilder mText;
Paint mPaint;
public MyCustomView(Context context) {
this(context, null, 0);
}
public MyCustomView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public MyCustomView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
private void init() {
setFocusableInTouchMode(true);
mText = new SpannableStringBuilder();
mPaint = new Paint();
mPaint.setColor(Color.BLACK);
mPaint.setTextSize(60);
mPaint.setStyle(Paint.Style.FILL);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawText(mText, 0, mText.length(), 50, 100, mPaint);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_UP) {
InputMethodManager imm = (InputMethodManager) getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
if (imm == null) return false;
imm.showSoftInput(this, InputMethodManager.SHOW_FORCED);
}
return true;
}
@Override
public InputConnection onCreateInputConnection(EditorInfo outAttrs) {
outAttrs.inputType = InputType.TYPE_CLASS_TEXT;
return new MyInputConnection(this, true);
}
}
MyInputConnection.java
public class MyInputConnection extends BaseInputConnection {
private MyCustomView customView;
MyInputConnection(View targetView, boolean fullEditor) {
super(targetView, fullEditor);
customView = (MyCustomView) targetView;
}
@Override
public Editable getEditable() {
return customView.mText;
}
@Override
public boolean commitText(CharSequence text, int newCursorPosition) {
boolean returnValue = super.commitText(text, newCursorPosition);
customView.invalidate();
return returnValue;
}
}
MainActivity.java
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
}
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<net.example.extractedtext.MyCustomView
android:id="@+id/myCustomView"
android:background="@android:color/holo_blue_bright"
android:layout_margin="50dp"
android:layout_width="300dp"
android:layout_height="150dp"
android:layout_centerHorizontal="true"
/>
</RelativeLayout>
Summary
I am looking for a canonical answer that describes and gives an example of how to implement extracted text updates for a custom editor view.
If I figure it out myself, I will add my own answer. Until then the best I have been able to do it just disable extracted text altogether. This is not ideal.