Skip to content

Commit

Permalink
Add C++ AndroidTextInput component for backwards-compatible Fabric su…
Browse files Browse the repository at this point in the history
…pport of TextInput on Android

Summary: Support existing, backwards-compatible AndroidTextInput component for minimal support of TextInput on Android.

Reviewed By: shergin, mdvacca

Differential Revision: D17086758

fbshipit-source-id: 25726f22229e0d5dfe96eb36b386a5317601283d
  • Loading branch information
JoshuaGross authored and facebook-github-bot committed Aug 31, 2019
1 parent 8981245 commit 5abe584
Show file tree
Hide file tree
Showing 13 changed files with 1,200 additions and 5 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
*/
package com.facebook.react.views.textinput;

import android.content.Context;
import android.graphics.PorterDuff;
import android.graphics.Typeface;
import android.graphics.drawable.Drawable;
Expand All @@ -20,6 +21,7 @@
import android.view.KeyEvent;
import android.view.View;
import android.view.inputmethod.EditorInfo;
import android.widget.EditText;
import android.widget.TextView;
import androidx.annotation.Nullable;
import androidx.core.content.ContextCompat;
Expand All @@ -29,6 +31,7 @@
import com.facebook.react.bridge.JSApplicationIllegalArgumentException;
import com.facebook.react.bridge.ReactContext;
import com.facebook.react.bridge.ReadableArray;
import com.facebook.react.bridge.ReadableMap;
import com.facebook.react.bridge.ReadableType;
import com.facebook.react.common.MapBuilder;
import com.facebook.react.module.annotations.ReactModule;
Expand All @@ -50,7 +53,9 @@
import com.facebook.react.views.text.ReactFontManager;
import com.facebook.react.views.text.ReactTextUpdate;
import com.facebook.react.views.text.TextInlineImageSpan;
import com.facebook.react.views.text.TextLayoutManager;
import com.facebook.yoga.YogaConstants;
import com.facebook.yoga.YogaMeasureMode;
import java.lang.reflect.Field;
import java.util.LinkedList;
import java.util.Map;
Expand Down Expand Up @@ -91,6 +96,8 @@ public class ReactTextInputManager extends BaseViewManager<ReactEditText, Layout
private static final InputFilter[] EMPTY_FILTERS = new InputFilter[0];
private static final int UNSET = -1;

@Nullable private static EditText mDummyEditText = null;

@Override
public String getName() {
return REACT_CLASS;
Expand Down Expand Up @@ -1075,4 +1082,18 @@ public void onScrollChanged(int horiz, int vert, int oldHoriz, int oldVert) {
"sentences",
InputType.TYPE_TEXT_FLAG_CAP_SENTENCES));
}
/** Measure function for Fabric. */
@Override
public long measure(
Context context,
ReadableMap localData,
ReadableMap props,
ReadableMap state,
float width,
YogaMeasureMode widthMode,
float height,
YogaMeasureMode heightMode) {
return TextLayoutManager.measureText(
context, localData, props, width, widthMode, height, heightMode);
}
}
3 changes: 1 addition & 2 deletions ReactCommon/fabric/components/slider/SliderShadowNode.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,8 @@
*/

#include "SliderShadowNode.h"
#include "SliderLocalData.h"

#include <react/components/slider/SliderLocalData.h>
#include <react/components/slider/SliderShadowNode.h>
#include <react/core/LayoutContext.h>

namespace facebook {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ namespace react {

AttributedString BaseTextShadowNode::getAttributedString(
const TextAttributes &textAttributes,
const SharedShadowNode &parentNode) const {
const SharedShadowNode &parentNode) {
auto attributedString = AttributedString{};

for (const auto &childNode : parentNode->getChildren()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,14 @@ class BaseTextShadowNode {
public:
/*
* Returns a `AttributedString` which represents text content of the node.
* This is static so that both Paragraph (which subclasses BaseText) and
* TextInput (which does not) can use this.
* TODO T53299884: decide if this should be moved out and made a static
* function, or if TextInput should inherit from BaseTextShadowNode.
*/
AttributedString getAttributedString(
static AttributedString getAttributedString(
const TextAttributes &baseTextAttributes,
const SharedShadowNode &parentNode) const;
const SharedShadowNode &parentNode);
};

} // namespace react
Expand Down
98 changes: 98 additions & 0 deletions ReactCommon/fabric/components/textinput/BUCK
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
load("@fbsource//tools/build_defs/apple:flag_defs.bzl", "get_debug_preprocessor_flags")
load(
"//tools/build_defs/oss:rn_defs.bzl",
"ANDROID",
"APPLE",
"CXX",
"YOGA_CXX_TARGET",
"fb_xplat_cxx_test",
"get_apple_compiler_flags",
"get_apple_inspector_flags",
"react_native_xplat_target",
"rn_xplat_cxx_library",
"subdir_glob",
)

APPLE_COMPILER_FLAGS = get_apple_compiler_flags()

rn_xplat_cxx_library(
name = "androidtextinput",
srcs = glob(
["**/*.cpp"],
exclude = glob(["tests/**/*.cpp"]),
),
headers = glob(
["**/*.h"],
exclude = glob(["tests/**/*.h"]),
),
header_namespace = "",
exported_headers = subdir_glob(
[
("", "*.h"),
("androidtextinput", "*.h"),
],
prefix = "react/components/androidtextinput",
),
compiler_flags = [
"-fexceptions",
"-frtti",
"-std=c++14",
"-Wall",
],
cxx_tests = [":tests"],
fbobjc_compiler_flags = APPLE_COMPILER_FLAGS,
fbobjc_preprocessor_flags = get_debug_preprocessor_flags() + get_apple_inspector_flags(),
force_static = True,
platforms = (ANDROID, APPLE, CXX),
preprocessor_flags = [
"-DLOG_TAG=\"ReactNative\"",
"-DWITH_FBSYSTRACE=1",
],
visibility = ["PUBLIC"],
deps = [
"fbsource//xplat/fbsystrace:fbsystrace",
"fbsource//xplat/folly:evicting_cache_map",
"fbsource//xplat/folly:headers_only",
"fbsource//xplat/folly:memory",
"fbsource//xplat/folly:molly",
"fbsource//xplat/third-party/glog:glog",
YOGA_CXX_TARGET,
react_native_xplat_target("utils:utils"),
react_native_xplat_target("fabric/attributedstring:attributedstring"),
react_native_xplat_target("fabric/core:core"),
react_native_xplat_target("fabric/debug:debug"),
react_native_xplat_target("fabric/graphics:graphics"),
react_native_xplat_target("fabric/textlayoutmanager:textlayoutmanager"),
react_native_xplat_target("fabric/components/text:text"),
react_native_xplat_target("fabric/components/view:view"),
react_native_xplat_target("fabric/components/image:image"),
react_native_xplat_target("fabric/uimanager:uimanager"),
react_native_xplat_target("fabric/imagemanager:imagemanager"),
],
)

fb_xplat_cxx_test(
name = "tests",
srcs = glob(["tests/**/*.cpp"]),
headers = glob(["tests/**/*.h"]),
compiler_flags = [
"-fexceptions",
"-frtti",
"-std=c++14",
"-Wall",
],
contacts = ["oncall+react_native@xmail.facebook.com"],
platforms = (
# `Apple` and `Android` flavors are disabled because the module depends on `textlayoutmanager` which requires real an Emulator/Simulator to run.
# At the same time, the code of tests does not rely on the simulator capabilities and it would be wasteful to add `fbandroid_use_instrumentation_test = True`.
# (Beware of this option though.)
# ANDROID,
# APPLE,
CXX
),
deps = [
"fbsource//xplat/folly:molly",
"fbsource//xplat/third-party/gmock:gtest",
":androidtextinput",
],
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/

#pragma once

#include <react/core/ConcreteComponentDescriptor.h>
#include "AndroidTextInputShadowNode.h"

namespace facebook {
namespace react {

/*
* Descriptor for <AndroidTextInput> component.
*/
class AndroidTextInputComponentDescriptor final
: public ConcreteComponentDescriptor<AndroidTextInputShadowNode> {
public:
AndroidTextInputComponentDescriptor(
EventDispatcher::Shared eventDispatcher,
const ContextContainer::Shared &contextContainer)
: ConcreteComponentDescriptor<AndroidTextInputShadowNode>(
eventDispatcher,
contextContainer) {}

protected:
void adopt(UnsharedShadowNode shadowNode) const override {
assert(std::dynamic_pointer_cast<AndroidTextInputShadowNode>(shadowNode));
auto concreteShadowNode =
std::static_pointer_cast<AndroidTextInputShadowNode>(shadowNode);

concreteShadowNode->setContextContainer(
const_cast<ContextContainer *>(getContextContainer().get()));

concreteShadowNode->dirtyLayout();
concreteShadowNode->enableMeasurement();

ConcreteComponentDescriptor::adopt(shadowNode);
}
};

} // namespace react
} // namespace facebook
Loading

0 comments on commit 5abe584

Please sign in to comment.