浏览代码

Merge branch 'dev_1.17.5' of github.com:Unity-Technologies/com.unity.uiwidgets into zxw/refine_debug_mode

# Conflicts:
#	com.unity.uiwidgets/Editor/UIWidgetsPanelEditor.cs
#	com.unity.uiwidgets/Runtime/engine2/UIWidgetsPanel.cs
/siyaoH-1.17-PlatformMessage
Xingwei Zhu 4 年前
当前提交
64720e9b
共有 41 个文件被更改,包括 1553 次插入74 次删除
  1. 1
      Samples/UIWidgetsSamples_2019_4/Assets/Script/CountTest.cs
  2. 1
      Samples/UIWidgetsSamples_2019_4/Assets/WidgetsSample/CustomPaintSample.cs
  3. 2
      Samples/UIWidgetsSamples_2019_4/Assets/WidgetsSample/DragDropSample.cs
  4. 99
      Samples/UIWidgetsSamples_2019_4/Assets/WidgetsSample/HttpRequestSample.cs
  5. 2
      Samples/UIWidgetsSamples_2019_4/Assets/WidgetsSample/LongPressSample.cs
  6. 1
      Samples/UIWidgetsSamples_2019_4/Assets/WidgetsSample/NavigationSample.cs
  7. 1
      Samples/UIWidgetsSamples_2019_4/Assets/WidgetsSample/PageViewSample.cs
  8. 1
      Samples/UIWidgetsSamples_2019_4/Assets/WidgetsSample/ScrollbarSample.cs
  9. 1
      Samples/UIWidgetsSamples_2019_4/Assets/WidgetsSample/ToDoAppSample.cs
  10. 38
      com.unity.uiwidgets/Runtime/engine/UIWidgetsMessageManager.cs
  11. 23
      com.unity.uiwidgets/Runtime/engine2/AndroidPlatformUtil.cs
  12. 102
      com.unity.uiwidgets/Runtime/engine2/DisplayMetrics.cs
  13. 25
      com.unity.uiwidgets/Runtime/engine2/UIWidgetsPanel.cs
  14. 2
      com.unity.uiwidgets/Runtime/engine2/UIWidgetsPanelWrapper.cs
  15. 1
      com.unity.uiwidgets/Runtime/rendering/binding.cs
  16. 15
      com.unity.uiwidgets/Runtime/services/keyboard.cs
  17. 3
      com.unity.uiwidgets/Runtime/services/text_input.cs
  18. 4
      com.unity.uiwidgets/Runtime/ui2/hooks.cs
  19. 5
      com.unity.uiwidgets/Runtime/ui2/window.cs
  20. 1
      com.unity.uiwidgets/Runtime/widgets/binding.cs
  21. 3
      engine/Build.bee.cs
  22. 88
      Samples/UIWidgetsSamples_2019_4/Assets/WidgetsSample/ImageFormatSample.cs
  23. 15
      engine/src/shell/platform/unity/darwin/ios/device_screen.mm
  24. 14
      engine/src/shell/platform/unity/darwin/ios/uiwidgets_device.h
  25. 140
      engine/src/shell/platform/unity/darwin/ios/uiwidgets_device.mm
  26. 44
      com.unity.uiwidgets/Runtime/Plugins/Android/UIWidgetsMessageManager.java
  27. 32
      com.unity.uiwidgets/Runtime/Plugins/Android/UIWidgetsMessageManager.java.meta
  28. 209
      com.unity.uiwidgets/Runtime/Plugins/Android/UIWidgetsViewController.java
  29. 32
      com.unity.uiwidgets/Runtime/Plugins/Android/UIWidgetsViewController.java.meta
  30. 13
      com.unity.uiwidgets/Runtime/Plugins/Android/UIWidgetsViewMetrics.java
  31. 32
      com.unity.uiwidgets/Runtime/Plugins/Android/UIWidgetsViewMetrics.java.meta
  32. 21
      com.unity.uiwidgets/Runtime/Plugins/Android/Utils.java
  33. 32
      com.unity.uiwidgets/Runtime/Plugins/Android/Utils.java.meta
  34. 229
      com.unity.uiwidgets/Runtime/Plugins/Android/InputConnectionAdaptor.java
  35. 31
      com.unity.uiwidgets/Runtime/Plugins/Android/InputConnectionAdaptor.java.meta
  36. 31
      com.unity.uiwidgets/Runtime/Plugins/Android/TextInputPlugin.java.meta
  37. 48
      com.unity.uiwidgets/Runtime/Plugins/Android/TextInputView.java
  38. 31
      com.unity.uiwidgets/Runtime/Plugins/Android/TextInputView.java.meta
  39. 254
      com.unity.uiwidgets/Runtime/Plugins/Android/TextInputPlugin.java

1
Samples/UIWidgetsSamples_2019_4/Assets/Script/CountTest.cs


{
return new WidgetsApp(
home: new ExampleApp(),
color: Color.white,
pageRouteBuilder: (settings, builder) =>
new PageRouteBuilder(
settings: settings,

1
Samples/UIWidgetsSamples_2019_4/Assets/WidgetsSample/CustomPaintSample.cs


public override Widget build(BuildContext context)
{
return new WidgetsApp(
color: Color.white,
home: new Unity.UIWidgets.widgets.CustomPaint(
child: new Container(width: 300, height: 300, color: new Color(0XFFFFFFFF)),
foregroundPainter: new GridPainter(null)

2
Samples/UIWidgetsSamples_2019_4/Assets/WidgetsSample/DragDropSample.cs


using Unity.UIWidgets.ui;
using Unity.UIWidgets.widgets;
using UnityEngine;
using Color = Unity.UIWidgets.ui.Color;
using ui_ = Unity.UIWidgets.widgets.ui_;
namespace UIWidgetsSample {

public override Widget build(BuildContext context)
{
return new WidgetsApp(
color: Color.white,
home: new DragDropApp(),
pageRouteBuilder: (settings, builder) =>
new PageRouteBuilder(

99
Samples/UIWidgetsSamples_2019_4/Assets/WidgetsSample/HttpRequestSample.cs


using UnityEngine.Networking;
using ui_ = Unity.UIWidgets.widgets.ui_;
public class HttpRequestSample : UIWidgetsPanel
namespace UIWidgetsSample
protected override void main() {
ui_.runApp(new MaterialApp(
title: "Http Request Sample",
home: new Scaffold(
body:new AsyncRequestWidget(this.gameObject)
public class HttpRequestSample : UIWidgetsPanel
{
protected override void main()
{
ui_.runApp(new MaterialApp(
title: "Http Request Sample",
home: new Scaffold(
body: new AsyncRequestWidget(this.gameObject)
));
));
}
}
public class AsyncRequestWidget : StatefulWidget {
public readonly GameObject gameObjOfUIWidgetsPanel;
public class AsyncRequestWidget : StatefulWidget
{
public AsyncRequestWidget(GameObject gameObjOfUiWidgetsPanel, Key key = null) : base(key) {
this.gameObjOfUIWidgetsPanel = gameObjOfUiWidgetsPanel;
public readonly GameObject gameObjOfUIWidgetsPanel;
public AsyncRequestWidget(GameObject gameObjOfUiWidgetsPanel, Key key = null) : base(key)
{
this.gameObjOfUIWidgetsPanel = gameObjOfUiWidgetsPanel;
}
public override State createState()
{
return new _AsyncRequestWidgetState();
}
public override State createState() {
return new _AsyncRequestWidgetState();
[Serializable]
public class TimeData
{
public long currentFileTime;
}
[Serializable]
public class TimeData {
public long currentFileTime;
}
class _AsyncRequestWidgetState : State<AsyncRequestWidget>
{
long _fileTime;
public override Widget build(BuildContext context)
{
var isolate = Isolate.current;
class _AsyncRequestWidgetState : State<AsyncRequestWidget> {
long _fileTime;
public override Widget build(BuildContext context) {
var isolate = Isolate.current;
return new Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: new List<Widget>() {
new FlatButton(child: new Text("Click To Get Time"), onPressed: () => {
UnityWebRequest www = UnityWebRequest.Get("http://worldclockapi.com/api/json/est/now");
var asyncOperation = www.SendWebRequest();
asyncOperation.completed += operation => {
var timeData = JsonUtility.FromJson<TimeData>(www.downloadHandler.text);
using(Isolate.getScope(isolate))
return new Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: new List<Widget>()
{
new FlatButton(child: new Text("Click To Get Time"), onPressed: () =>
{
UnityWebRequest www = UnityWebRequest.Get("http://worldclockapi.com/api/json/est/now");
var asyncOperation = www.SendWebRequest();
asyncOperation.completed += operation =>
this.setState(() => { this._fileTime = timeData.currentFileTime; });
}
};
}),
new Text($"current file time: {this._fileTime}")
});
var timeData = JsonUtility.FromJson<TimeData>(www.downloadHandler.text);
using (Isolate.getScope(isolate))
{
this.setState(() => { this._fileTime = timeData.currentFileTime; });
}
};
}),
new Text($"current file time: {this._fileTime}")
});
}
}
}

2
Samples/UIWidgetsSamples_2019_4/Assets/WidgetsSample/LongPressSample.cs


using Unity.UIWidgets.engine2;
using Unity.UIWidgets.widgets;
using UnityEngine;
using Color = Unity.UIWidgets.ui.Color;
namespace UIWidgetsSample {
public class LongPressSample : UIWidgetsPanel {

public override Widget build(BuildContext context)
{
return new WidgetsApp(
color: Color.white,
home: new LongPressSampleWidget(),
pageRouteBuilder: (settings, builder) =>
new PageRouteBuilder(

1
Samples/UIWidgetsSamples_2019_4/Assets/WidgetsSample/NavigationSample.cs


public override Widget build(BuildContext context)
{
return new WidgetsApp(
color: Color.white,
initialRoute: "/",
textStyle: new TextStyle(fontSize: 24),
pageRouteBuilder: (settings, builder) =>

1
Samples/UIWidgetsSamples_2019_4/Assets/WidgetsSample/PageViewSample.cs


public override Widget build(BuildContext context)
{
return new WidgetsApp(
color: Color.white,
home: new Container(
width: 200,
height: 400,

1
Samples/UIWidgetsSamples_2019_4/Assets/WidgetsSample/ScrollbarSample.cs


public override Widget build(BuildContext context)
{
return new WidgetsApp(
color: Color.white,
home: new Container(
decoration: new BoxDecoration(
border: Border.all(color: new Color(0xFFFFFF00))

1
Samples/UIWidgetsSamples_2019_4/Assets/WidgetsSample/ToDoAppSample.cs


{
ui_.runApp(
new WidgetsApp(
color: Color.white,
home: new ToDoListApp(),
pageRouteBuilder: this.pageRouteBuilder)
);

38
com.unity.uiwidgets/Runtime/engine/UIWidgetsMessageManager.cs


}
void UpdateNameIfNeed() {
#if UNITY_IOS || UNITY_ANDROID || UNITY_WEBGL
/*var name = gameObject.name;
#if UNITY_ANDROID || UNITY_WEBGL
var name = gameObject.name;
if (name != _lastObjectName) {
if (!Application.isEditor) {

}*/
}
#endif
}

}
}
Queue<string> messages = new Queue<string>();
JSONObject jsonObject = (JSONObject)JSON.Parse(message);
string channel = jsonObject["channel"].Value;
string method = jsonObject["method"].Value;
var args = new List<JSONNode>(jsonObject["args"].AsArray.Children);
if (string.IsNullOrEmpty(channel) || string.IsNullOrEmpty(method)) {
Debug.LogError("invalid uiwidgets method message");
}
else {
MethodChannelMessageDelegate exists;
_methodChannelMessageDelegates.TryGetValue(channel, out exists);
exists?.Invoke(method, args);
messages.Enqueue(message);
}
public void handlePlatformMessage(){
while (!messages.isEmpty()) {
var message = messages.Dequeue();
JSONObject jsonObject = (JSONObject) JSON.Parse(message);
string channel = jsonObject["channel"].Value;
string method = jsonObject["method"].Value;
var args = new List<JSONNode>(jsonObject["args"].AsArray.Children);
if (string.IsNullOrEmpty(channel) || string.IsNullOrEmpty(method)) {
Debug.LogError("invalid uiwidgets method message");
}
else {
MethodChannelMessageDelegate exists;
_methodChannelMessageDelegates.TryGetValue(channel, out exists);
exists?.Invoke(method, args);
}
}
}

23
com.unity.uiwidgets/Runtime/engine2/AndroidPlatformUtil.cs


#if !UNITY_EDITOR && UNITY_ANDROID
using UnityEngine;
using AOT;
using System;
public static class UIWidgetsAndroidConfiguration{
public const bool showStatusBar = true;
}
[DllImport(NativeBindings.dllName)]
internal static extern void InitUnpackFile(UnpackFileCallback unpack);

var dir = Application.temporaryCachePath + "/";
if (!File.Exists(dir + file)) {
var path = "jar:file://" + Application.dataPath + "!/assets/" + file;
using(var unpackerWWW = UnityWebRequest.Get(path)) {
using (var unpackerWWW = UnityWebRequest.Get(path)) {
File.WriteAllBytes(fileInfo.FullName, data);
File.WriteAllBytes(fileInfo.FullName, data);
[DllImport(NativeBindings.dllName)]
static extern System.IntPtr GetUnityContextEventFunc();

if( UIWidgetsAndroidConfiguration.showStatusBar){
ShowStatusBar(true);
}
}
public static void ShowStatusBar(bool value) {
using (var util = new AndroidJavaClass("com.unity.uiwidgets.plugin.Utils")) {
util.CallStatic("SetStatusBarState", value);
}
}
}
}

102
com.unity.uiwidgets/Runtime/engine2/DisplayMetrics.cs


using System.Runtime.InteropServices;
using Unity.UIWidgets.ui;
[StructLayout(LayoutKind.Sequential)]
public struct viewMetrics {
public float insets_top;
public float insets_bottom;
public float insets_left;
public float insets_right;
public float padding_top;
public float padding_bottom;
public float padding_left;
public float padding_right;
}
public class DisplayMetrics {
float _devicePixelRatioByDefault;

return _devicePixelRatioByDefault;
}
#if UNITY_IOS
_devicePixelRatioByDefault = IOSDeviceScaleFactor();
#endif
if (_devicePixelRatioByDefault <= 0) {
_devicePixelRatioByDefault = 1;
}

}
public WindowPadding viewPadding {
get {
return new WindowPadding(viewMetrics.padding_left,
viewMetrics.padding_top,
viewMetrics.padding_right,
viewMetrics.padding_bottom);
}
}
public WindowPadding viewInsets {
get {
return new WindowPadding(viewMetrics.insets_left,
viewMetrics.insets_top,
viewMetrics.insets_right,
viewMetrics.insets_bottom);
}
}
private viewMetrics? _viewMetrics;
public viewMetrics viewMetrics {
get {
if (_viewMetrics != null) {
return _viewMetrics.Value;
}
#if UNITY_ANDROID && !UNITY_EDITOR
using (
AndroidJavaClass viewController =
new AndroidJavaClass("com.unity.uiwidgets.plugin.UIWidgetsViewController")
) {
AndroidJavaObject metrics = viewController.CallStatic<AndroidJavaObject>("getMetrics");
float insets_bottom = metrics.Get<float>("insets_bottom");
float insets_top = metrics.Get<float>("insets_top");
float insets_left = metrics.Get<float>("insets_left");
float insets_right = metrics.Get<float>("insets_right");
float padding_bottom = metrics.Get<float>("padding_bottom");
float padding_top = metrics.Get<float>("padding_top");
float padding_left = metrics.Get<float>("padding_left");
float padding_right = metrics.Get<float>("padding_right");
_viewMetrics = new viewMetrics {
insets_bottom = insets_bottom,
insets_left = insets_left,
insets_right = insets_right,
insets_top = insets_top,
padding_left = padding_left,
padding_top = padding_top,
padding_right = padding_right,
padding_bottom = padding_bottom
};
}
#else
_viewMetrics = new viewMetrics {
insets_bottom = 0,
insets_left = 0,
insets_right = 0,
insets_top = 0,
padding_left = 0,
padding_top = 0,
padding_right = 0,
padding_bottom = 0
};
#endif
return _viewMetrics.Value;
}
}
public void onViewMetricsChanged() {
//view metrics marks dirty
_viewMetrics = null;
}
#if UNITY_ANDROID
static float AndroidDevicePixelRatio() {
using (

}
}
}
#endif
#if UNITY_IOS
        [DllImport("__Internal")]
        static extern float IOSDeviceScaleFactor();
//         [DllImport(“__Internal”)]
//         static extern viewMetrics IOSGetViewportPadding();
#endif
}

25
com.unity.uiwidgets/Runtime/engine2/UIWidgetsPanel.cs


using System;
using System.Collections;
using System.Collections.Generic;
using Unity.UIWidgets.engine;
using Unity.UIWidgets.engine2;
using Unity.UIWidgets.external.simplejson;
using Unity.UIWidgets.widgets;
using RawImage = UnityEngine.UI.RawImage;
namespace Unity.UIWidgets.engine2 {
public enum UIWidgetsWindowType {

public bool enableDebugAtRuntime = false;
DisplayMetrics _displayMetrics = new DisplayMetrics();
float _devicePixelRatioOverride;
public bool hardwareAntiAliasing;

float _currentDevicePixelRatio {
get {
#if !UNITY_EDITOR
return _displayMetrics.DevicePixelRatioByDefault;
return _wrapper.displayMetrics.DevicePixelRatioByDefault;
#endif
var currentDpi = Screen.dpi;
if (currentDpi == 0) {

return currentDpi / 96;
}
}
bool _viewMetricsCallbackRegistered;
void _handleViewMetricsChanged(string method, List<JSONNode> args) {
_wrapper.displayMetrics.onViewMetricsChanged();
Window.instance.updateSafeArea();
Window.instance.onMetricsChanged?.Invoke();
}
UIWidgetsMessageManager.ensureUIWidgetsMessageManagerIfNeeded();
if (!_viewMetricsCallbackRegistered) {
_viewMetricsCallbackRegistered = true;
UIWidgetsMessageManager.instance?.AddChannelMessageDelegate("ViewportMetricsChanged",
_handleViewMetricsChanged);
}
Input_Update();
}

2
com.unity.uiwidgets/Runtime/engine2/UIWidgetsPanelWrapper.cs


public Isolate isolate { get; private set; }
public float devicePixelRatio { get; private set; }
public DisplayMetrics displayMetrics = new DisplayMetrics();
public void Initiate(IUIWidgetsWindow host, int width, int height, float dpr, Configurations _configurations) {
D.assert(renderTexture == null);

1
com.unity.uiwidgets/Runtime/rendering/binding.cs


D.assert(renderView != null);
addPersistentFrameCallback(_handlePersistentFrameCallback);
initMouseTracker();
window.updateSafeArea();
}
public void initRenderView() {

15
com.unity.uiwidgets/Runtime/services/keyboard.cs


public abstract void setEditingState(TextEditingValue value);
public void setEditableSizeAndTransform(Dictionary<string, object> args) {
throw new NotImplementedException();
Debug.LogError("not implemented yet");
throw new NotImplementedException();
Debug.LogError("not implemented yet");
}
public abstract void setIMEPos(Offset imeGlobalPos);

}
void _handleMethodCall(string method, List<JSONNode> args) {
D.assert(false, () => "keyboard.handleMethodCall is not implemented yet!");
/*if (TextInput._currentConnection == null) {
if (TextInput._currentConnection == null) {
return;
}
int client = args[0].AsInt;

using (TextInput._currentConnection._window.getScope()) {
var isolate = Isolate.current;
using (Isolate.getScope(isolate)) {
TextInput._updateEditingState(client, TextEditingValue.fromJson(args[1].AsObject));
TextInput._updateEditingState(client, TextEditingValue.fromJSON(args[1].AsObject));
break;
case "TextInputClient.performAction":
TextInput._performAction(client, TextInputUtils._toTextInputAction(args[1].Value));

}
}*/
}
}
}

3
com.unity.uiwidgets/Runtime/services/text_input.cs


this.obscureText = obscureText;
this.autocorrect = autocorrect;
this.enableSuggestions = enableSuggestions;
this.actionLabel = actionLabel;
this.actionLabel = actionLabel ?? "";
this.inputAction = inputAction;
this.textCapitalization = textCapitalization;
this.keyboardAppearance = keyboardAppearance;

else {
keyboardDelegate = new UIWidgetsTouchScreenKeyboardDelegate();
}*/
keyboardDelegate = new UIWidgetsTouchScreenKeyboardDelegate();
#elif UNITY_WEBGL
keyboardDelegate = new UIWidgetsWebGLKeyboardDelegate();
#else

4
com.unity.uiwidgets/Runtime/ui2/hooks.cs


using System.Runtime.InteropServices;
using AOT;
using Unity.UIWidgets.async2;
using Unity.UIWidgets.engine;
using Unity.UIWidgets.foundation;
using Unity.UIWidgets.ui;
using UnityEngine;

[MonoPInvokeCallback(typeof(Window_drawFrameCallback))]
static void Window_drawFrame() {
try {
#if !UNITY_EDITOR && UNITY_ANDROID
UIWidgetsMessageManager.instance.handlePlatformMessage();
#endif
Window.instance.onDrawFrame?.Invoke();
}
catch (Exception ex) {

5
com.unity.uiwidgets/Runtime/ui2/window.cs


}
}
public void updateSafeArea() {
padding = _panel.displayMetrics.viewPadding;
viewInsets = _panel.displayMetrics.viewInsets;
}
public void scheduleFrame() {
Window_scheduleFrame(_ptr);
_panel.window.onNewFrameScheduled();

1
com.unity.uiwidgets/Runtime/widgets/binding.cs


public void attachRootWidget(Widget rootWidget) {
_readyToProduceFrames = true;
_renderViewElement = new RenderObjectToWidgetAdapter<RenderBox>(
container: renderView,
debugShortDescription: "[root]",

3
engine/Build.bee.cs


"src/shell/platform/unity/darwin/ios/cocoa_task_runner.h",
"src/shell/platform/unity/darwin/ios/unity_surface_manager.mm",
"src/shell/platform/unity/darwin/ios/unity_surface_manager.h",
"src/shell/platform/unity/darwin/ios/device_screen.mm",
"src/shell/platform/unity/darwin/ios/uiwidgets_device.mm",
"src/shell/platform/unity/darwin/ios/uiwidgets_device.h",
};
np.Sources.Add(c => IsWindows(c), winSources);

88
Samples/UIWidgetsSamples_2019_4/Assets/WidgetsSample/ImageFormatSample.cs


using System.Collections.Generic;
using uiwidgets;
using Unity.UIWidgets.engine2;
using Unity.UIWidgets.painting;
using Unity.UIWidgets.ui;
using Unity.UIWidgets.widgets;
using Image = Unity.UIWidgets.widgets.Image;
using ui_ = Unity.UIWidgets.widgets.ui_;
namespace UIWidgetsSample
{
public class ImageFormatSample : UIWidgetsPanel
{
protected override void main()
{
ui_.runApp(new MyApp());
}
class MyApp : StatelessWidget
{
public override Widget build(BuildContext context)
{
return new WidgetsApp(
home: new ImageFormatApp(),
color: Color.white,
pageRouteBuilder: (settings, builder) =>
new PageRouteBuilder(
settings: settings,
pageBuilder: (buildContext, animation, secondaryAnimation) => builder(context)
)
);
}
}
class ImageFormatApp : StatefulWidget
{
public override State createState()
{
return new ImageFormatAppState();
}
}
class ImageFormatAppState : State<ImageFormatApp>
{
private int imageId;
private static List<string> imagePath = new List<string>
{
"shrine_images/0-0.jpg",
"shrine_images/2.0x/1-0.jpg",
"shrine_images/diamond.png",
"gallery/people/square/ali.png",
"gallery/10-0.jpg",
"gallery/glasses.jpg"
};
public override Widget build(BuildContext context)
{
return new Container(
child: new Column(
children: new List<Widget>
{
new Container(
width: 100,
height: 100,
decoration: new BoxDecoration(
borderRadius: BorderRadius.all(Radius.circular(8))
),
child: Image.file(imagePath[imageId])
),
new Text(imagePath[imageId]),
new GestureDetector(
onTap: () => { setState(() => { imageId = (imageId + 1) % imagePath.Count; }); },
child: new Container(
color: Color.black,
padding: EdgeInsets.symmetric(20, 20),
child: new Text("Next"
)
))
}
));
}
}
}
}

15
engine/src/shell/platform/unity/darwin/ios/device_screen.mm


#import <UIKit/UIKit.h>
#import "uiwidgets_device.h"
#include "runtime/mono_api.h"
namespace uiwidgets {
UIWIDGETS_API(float) IOSDeviceScaleFactor()
{
float scale = [[UIScreen mainScreen] scale] * 1.0;
if ([UIWidgetsDevice NeedScreenDownSample]) {
scale *= 0.8696;
}
return scale;
}
}

14
engine/src/shell/platform/unity/darwin/ios/uiwidgets_device.h


#ifndef UIWidgetsDevice_h
#define UIWidgetsDevice_h
#import <UIKit/UIKit.h>
@interface UIWidgetsDevice : NSObject
+(NSString *) deviceName;
+(BOOL) NeedScreenDownSample;
@end
#endif

140
engine/src/shell/platform/unity/darwin/ios/uiwidgets_device.mm


#include "uiwidgets_device.h"
#import <sys/utsname.h>
#import <UIKit/UIKit.h>
static NSString* _deviceName = nil;
@implementation UIWidgetsDevice
+ (NSString *) deviceName
{
if (_deviceName != nil) {
return _deviceName;
}
struct utsname systemInfo;
uname(&systemInfo);
NSString* code = [NSString stringWithCString:systemInfo.machine encoding:NSUTF8StringEncoding];
NSDictionary* deviceNamesByCode = @{
@"i386" : @"Simulator",
@"x86_64" : @"Simulator",
@"iPod1,1" : @"iPod Touch", // (Original)
@"iPod2,1" : @"iPod Touch", // (Second Generation)
@"iPod3,1" : @"iPod Touch", // (Third Generation)
@"iPod4,1" : @"iPod Touch", // (Fourth Generation)
@"iPod7,1" : @"iPod Touch", // (6th Generation)
@"iPhone1,1" : @"iPhone", // (Original)
@"iPhone1,2" : @"iPhone", // (3G)
@"iPhone2,1" : @"iPhone", // (3GS)
@"iPad1,1" : @"iPad", // (Original)
@"iPad2,1" : @"iPad 2", //
@"iPad3,1" : @"iPad", // (3rd Generation)
@"iPhone3,1" : @"iPhone 4", // (GSM)
@"iPhone3,3" : @"iPhone 4", // (CDMA/Verizon/Sprint)
@"iPhone4,1" : @"iPhone 4S", //
@"iPhone5,1" : @"iPhone 5", // (model A1428, AT&T/Canada)
@"iPhone5,2" : @"iPhone 5", // (model A1429, everything else)
@"iPad3,4" : @"iPad", // (4th Generation)
@"iPad2,5" : @"iPad Mini", // (Original)
@"iPhone5,3" : @"iPhone 5C", // (model A1456, A1532 | GSM)
@"iPhone5,4" : @"iPhone 5C", // (model A1507, A1516, A1526 (China), A1529 | Global)
@"iPhone6,1" : @"iPhone 5S", // (model A1433, A1533 | GSM)
@"iPhone6,2" : @"iPhone 5S", // (model A1457, A1518, A1528 (China), A1530 | Global)
@"iPhone7,1" : @"iPhone 6 Plus", //
@"iPhone7,2" : @"iPhone 6", //
@"iPhone8,1" : @"iPhone 6S", //
@"iPhone8,2" : @"iPhone 6S Plus", //
@"iPhone8,4" : @"iPhone SE", //
@"iPhone9,1" : @"iPhone 7", //
@"iPhone9,3" : @"iPhone 7", //
@"iPhone9,2" : @"iPhone 7 Plus", //
@"iPhone9,4" : @"iPhone 7 Plus", //
@"iPhone10,1": @"iPhone 8", // CDMA
@"iPhone10,4": @"iPhone 8", // GSM
@"iPhone10,2": @"iPhone 8 Plus", // CDMA
@"iPhone10,5": @"iPhone 8 Plus", // GSM
@"iPhone10,3": @"iPhone X", // CDMA
@"iPhone10,6": @"iPhone X", // GSM
@"iPhone11,2": @"iPhone XS", //
@"iPhone11,4": @"iPhone XS Max", //
@"iPhone11,6": @"iPhone XS Max", // China
@"iPhone11,8": @"iPhone XR", //
@"iPad4,1" : @"iPad Air", // 5th Generation iPad (iPad Air) - Wifi
@"iPad4,2" : @"iPad Air", // 5th Generation iPad (iPad Air) - Cellular
@"iPad4,4" : @"iPad Mini", // (2nd Generation iPad Mini - Wifi)
@"iPad4,5" : @"iPad Mini", // (2nd Generation iPad Mini - Cellular)
@"iPad4,7" : @"iPad Mini", // (3rd Generation iPad Mini - Wifi (model A1599))
@"iPad6,7" : @"iPad Pro (12.9\")", // iPad Pro 12.9 inches - (model A1584)
@"iPad6,8" : @"iPad Pro (12.9\")", // iPad Pro 12.9 inches - (model A1652)
@"iPad6,3" : @"iPad Pro (9.7\")", // iPad Pro 9.7 inches - (model A1673)
@"iPad6,4" : @"iPad Pro (9.7\")"
};
_deviceName = [deviceNamesByCode objectForKey:code];
if (!_deviceName) {
if ([code rangeOfString:@"iPod"].location != NSNotFound) {
_deviceName = @"iPod Touch";
}
else if([code rangeOfString:@"iPad"].location != NSNotFound) {
_deviceName = @"iPad";
}
else if([code rangeOfString:@"iPhone"].location != NSNotFound){
_deviceName = @"iPhone";
}
else {
_deviceName = @"Unknown";
}
}
if ([_deviceName isEqualToString:@"Simulator"]) {
if([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone) {
switch ((int)[[UIScreen mainScreen] nativeBounds].size.height) {
//iPhone 5 or 5S or 5C
case 1136:
_deviceName = @"iPhone 5 Simulator";
break;
//iPhone 6 or 6S or 7 or 8
case 1334:
_deviceName = @"iPhone 6 Simulator";
break;
//iPhone 6+ or 6S+ or 7+ or 8+
case 1920:
_deviceName = @"iPhone 6 Plus Simulator";
break;
//iPhone 6+ or 6S+ or 7+ or 8+
case 2208:
_deviceName = @"iPhone 6 Plus Simulator";
break;
//iPhone X or XS
case 2436:
_deviceName = @"iPhone X Simulator";
break;
//iPhone XS Max
case 2688:
_deviceName = @"iPhone XS Max Simulator";
break;
//iPhone XR
case 1792:
_deviceName = @"iPhone XR Simulator";
break;
default:
_deviceName = @"Unknown Simulator";
break;
}
}
}
return _deviceName;
}
+ (BOOL) NeedScreenDownSample
{
return [[UIWidgetsDevice deviceName] isEqualToString:@"iPhone 6 Plus"] ||
[[UIWidgetsDevice deviceName] isEqualToString:@"iPhone 6S Plus"] ||
[[UIWidgetsDevice deviceName] isEqualToString:@"iPhone 7 Plus"] ||
[[UIWidgetsDevice deviceName] isEqualToString:@"iPhone 8 Plus"];
}
@end

44
com.unity.uiwidgets/Runtime/Plugins/Android/UIWidgetsMessageManager.java


package com.unity.uiwidgets.plugin;
import android.util.Log;
import com.unity3d.player.UnityPlayer;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.util.List;
public class UIWidgetsMessageManager {
public static final String TAG = "UIWidgets";
private static UIWidgetsMessageManager _instance;
private String gameObjectName;
public static UIWidgetsMessageManager getInstance() {
if (_instance == null) {
_instance = new UIWidgetsMessageManager();
}
return _instance;
}
public void SetObjectName(String name) {
gameObjectName = name;
}
public void UIWidgetsMethodMessage(String channel, String method, List<Object> args) {
JSONObject object = new JSONObject();
try {
object.put("channel", channel);
object.put("method", method);
object.put("args", new JSONArray(args));
UnityPlayer.UnitySendMessage(gameObjectName, "OnUIWidgetsMethodMessage", object.toString());
} catch (JSONException e) {
Log.e(TAG, "error parse json", e);
}
}
}

32
com.unity.uiwidgets/Runtime/Plugins/Android/UIWidgetsMessageManager.java.meta


fileFormatVersion: 2
guid: fbff29dbbe1ce46a5bd2b95fef473852
PluginImporter:
externalObjects: {}
serializedVersion: 2
iconMap: {}
executionOrder: {}
defineConstraints: []
isPreloaded: 0
isOverridable: 1
isExplicitlyReferenced: 0
validateReferences: 1
platformData:
- first:
Android: Android
second:
enabled: 1
settings: {}
- first:
Any:
second:
enabled: 0
settings: {}
- first:
Editor: Editor
second:
enabled: 0
settings:
DefaultValueInitialized: true
userData:
assetBundleName:
assetBundleVariant:

209
com.unity.uiwidgets/Runtime/Plugins/Android/UIWidgetsViewController.java


package com.unity.uiwidgets.plugin;
import android.util.Log;
import com.unity3d.player.UnityPlayer;
import android.graphics.Rect;
import android.os.Build;
import android.util.Log;
import android.util.TypedValue;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
import android.app.Activity;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.view.Surface;
import java.util.Arrays;
import android.view.WindowManager;
import android.os.Handler;
import java.lang.reflect.Method;
public class UIWidgetsViewController {
private static UIWidgetsViewController _instance;
public static UIWidgetsViewController getInstance() {
if (_instance == null) {
_instance = new UIWidgetsViewController();
_instance.setup();
}
return _instance;
}
private UIWidgetsViewMetrics viewMetrics;
private boolean keyboardOpen;
private float statusHeight;
private float navigationBarHeight;
private void setup() {
keyboardOpen = false;
viewMetrics = new UIWidgetsViewMetrics();
setupHeights();
updateViewMetrics();
setupViewMetricsChangedListener();
}
private void setupHeights() {
final View unityView = ((ViewGroup)UnityPlayer.currentActivity.findViewById(android.R.id.content)).getChildAt(0);
Rect rect = new Rect();
unityView.getWindowVisibleDisplayFrame(rect);
statusHeight = rect.top;
navigationBarHeight = unityView.getRootView().getHeight() - rect.bottom;
}
public static UIWidgetsViewMetrics getMetrics() {
UIWidgetsViewController controller = getInstance();
return controller.viewMetrics;
}
enum ZeroSides { NONE, LEFT, RIGHT, BOTH }
ZeroSides calculateShouldZeroSides(View unityView) {
Activity activity = UnityPlayer.currentActivity;
int orientation = activity.getResources().getConfiguration().orientation;
int rotation = activity.getWindowManager().getDefaultDisplay().getRotation();
if (orientation == Configuration.ORIENTATION_LANDSCAPE) {
if (rotation == Surface.ROTATION_90) {
return ZeroSides.RIGHT;
}
else if (rotation == Surface.ROTATION_270) {
return Build.VERSION.SDK_INT >= 23 ? ZeroSides.LEFT : ZeroSides.RIGHT;
} else if (rotation == Surface.ROTATION_0 || rotation == Surface.ROTATION_180) {
return ZeroSides.BOTH;
}
}
return ZeroSides.NONE;
}
public boolean lastStatusBarHidden = true;
private int calculateBottomKeyboardInset(Rect insets) {
if (keyboardOpen) {
return insets.bottom;
} else {
return 0;
}
}
private int getNavigationBarHeight() {
Resources resources = UnityPlayer.currentActivity.getResources();
int resourceId = resources.getIdentifier("navigation_bar_height", "dimen", "android");
if (resourceId > 0)
{
return hasNavigationBar() ? resources.getDimensionPixelSize(resourceId) : 0;
}
return 0;
}
private boolean hasNavigationBar() {
boolean hasBar = false;
Resources resources = UnityPlayer.currentActivity.getResources();
int id = resources.getIdentifier("config_showNavigationBar", "bool", "android");
if (id > 0) {
hasBar = resources.getBoolean(id);
}
try {
Class systemPropertiesClass = Class.forName("android.os.SystemProperties");
Method m = systemPropertiesClass.getMethod("get", String.class);
String navBarOverride = (String) m.invoke(systemPropertiesClass, "qemu.hw.mainkeys");
if ("1".equals(navBarOverride)) {
hasBar = false;
} else if ("0".equals(navBarOverride)) {
hasBar = true;
}
} catch (Exception e) {
e.printStackTrace();
}
return hasBar;
}
public void updateViewMetrics() {
final View unityView = ((ViewGroup)UnityPlayer.currentActivity.findViewById(android.R.id.content)).getChildAt(0);
Rect rect = new Rect();
unityView.getWindowVisibleDisplayFrame(rect);
rect.bottom = unityView.getRootView().getHeight() - (rect.bottom - rect.top) - rect.top;
// rect.right = unityView.getRootView().getWidth() - (rect.right - rect.left) - rect.left;
boolean statusBarHidden = (View.SYSTEM_UI_FLAG_FULLSCREEN & unityView.getWindowSystemUiVisibility()) != 0;
boolean navigationBarHidden = (View.SYSTEM_UI_FLAG_HIDE_NAVIGATION & unityView.getWindowSystemUiVisibility()) != 0;
ZeroSides zeroSides = ZeroSides.NONE;
if (navigationBarHidden) {
zeroSides = calculateShouldZeroSides(unityView);
}
// viewMetrics.padding_top = rect.top;
// viewMetrics.padding_right = zeroSides == ZeroSides.RIGHT || zeroSides == ZeroSides.BOTH ? 0 : rect.right;
// viewMetrics.padding_bottom = 0;
// viewMetrics.padding_left = zeroSides == ZeroSides.LEFT || zeroSides == ZeroSides.BOTH ? 0 : rect.left;
viewMetrics.insets_top = 0;
viewMetrics.insets_right = 0;
viewMetrics.insets_bottom = navigationBarHidden? calculateBottomKeyboardInset(rect) : rect.bottom;
viewMetrics.insets_left = 0;
//adjust
viewMetrics.insets_bottom -= navigationBarHeight;
// viewMetrics.padding_top -= statusHeight;
}
public void setupViewMetricsChangedListener() {
final View unityView = ((ViewGroup)UnityPlayer.currentActivity.findViewById(android.R.id.content)).getChildAt(0);
UnityPlayer.currentActivity.runOnUiThread(new Runnable() {
@Override
public void run() {
unityView.setOnSystemUiVisibilityChangeListener(new View.OnSystemUiVisibilityChangeListener() {
@Override
public void onSystemUiVisibilityChange(final int visibility){
boolean statusBarHidden = (View.SYSTEM_UI_FLAG_FULLSCREEN & visibility) != 0;
unityView.setSystemUiVisibility(visibility);
UIWidgetsViewController controller = getInstance();
if (statusBarHidden != controller.lastStatusBarHidden) {
controller.onViewMetricsChanged();
}
}
});
}
});
unityView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
private final int defaultKeyboardHeightDP = 100;
private final int estimatedKeyboardDP = defaultKeyboardHeightDP + (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP ? 48 : 0);
private final Rect rect = new Rect();
@Override
public void onGlobalLayout() {
int estimatedKeyboardHeight = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, estimatedKeyboardDP, unityView.getResources().getDisplayMetrics());
unityView.getWindowVisibleDisplayFrame(rect);
int heightDiff = unityView.getRootView().getHeight() - (rect.bottom - rect.top);
boolean isShown = heightDiff >= estimatedKeyboardHeight;
if (keyboardOpen == isShown) {
return;
}
keyboardOpen = isShown;
onViewMetricsChanged();
}
}
);
}
public void onViewMetricsChanged() {
updateViewMetrics();
UIWidgetsMessageManager.getInstance().UIWidgetsMethodMessage("ViewportMetricsChanged", "UIWidgetViewController.keyboardChanged",
Arrays.asList(""));
}
}

32
com.unity.uiwidgets/Runtime/Plugins/Android/UIWidgetsViewController.java.meta


fileFormatVersion: 2
guid: dd01a28ebf279449dace0dc8580a9ece
PluginImporter:
externalObjects: {}
serializedVersion: 2
iconMap: {}
executionOrder: {}
defineConstraints: []
isPreloaded: 0
isOverridable: 1
isExplicitlyReferenced: 0
validateReferences: 1
platformData:
- first:
Android: Android
second:
enabled: 1
settings: {}
- first:
Any:
second:
enabled: 0
settings: {}
- first:
Editor: Editor
second:
enabled: 0
settings:
DefaultValueInitialized: true
userData:
assetBundleName:
assetBundleVariant:

13
com.unity.uiwidgets/Runtime/Plugins/Android/UIWidgetsViewMetrics.java


package com.unity.uiwidgets.plugin;
public class UIWidgetsViewMetrics {
public float insets_top;
public float insets_bottom;
public float insets_left;
public float insets_right;
public float padding_top;
public float padding_bottom;
public float padding_left;
public float padding_right;
}

32
com.unity.uiwidgets/Runtime/Plugins/Android/UIWidgetsViewMetrics.java.meta


fileFormatVersion: 2
guid: efb8c112055a04b7dae8566ccf299bc7
PluginImporter:
externalObjects: {}
serializedVersion: 2
iconMap: {}
executionOrder: {}
defineConstraints: []
isPreloaded: 0
isOverridable: 1
isExplicitlyReferenced: 0
validateReferences: 1
platformData:
- first:
Android: Android
second:
enabled: 1
settings: {}
- first:
Any:
second:
enabled: 0
settings: {}
- first:
Editor: Editor
second:
enabled: 0
settings:
DefaultValueInitialized: true
userData:
assetBundleName:
assetBundleVariant:

21
com.unity.uiwidgets/Runtime/Plugins/Android/Utils.java


package com.unity.uiwidgets.plugin;
import android.view.View;
import android.view.WindowManager;
import com.unity3d.player.UnityPlayer;
public class Utils {
public static final String TAG = "UIWidgets";
public static void SetStatusBarState(final boolean show) {
UnityPlayer.currentActivity.runOnUiThread(new Runnable() {
public void run() {
if (show) {
UnityPlayer.currentActivity.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
} else {
UnityPlayer.currentActivity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
}
}
});
}
}

32
com.unity.uiwidgets/Runtime/Plugins/Android/Utils.java.meta


fileFormatVersion: 2
guid: 418c6c9d61a804a9e817e77aa7f83f67
PluginImporter:
externalObjects: {}
serializedVersion: 2
iconMap: {}
executionOrder: {}
defineConstraints: []
isPreloaded: 0
isOverridable: 1
isExplicitlyReferenced: 0
validateReferences: 1
platformData:
- first:
Android: Android
second:
enabled: 1
settings: {}
- first:
Any:
second:
enabled: 0
settings: {}
- first:
Editor: Editor
second:
enabled: 0
settings:
DefaultValueInitialized: true
userData:
assetBundleName:
assetBundleVariant:

229
com.unity.uiwidgets/Runtime/Plugins/Android/InputConnectionAdaptor.java


package com.unity.uiwidgets.plugin.editing;
import android.content.Context;
import android.text.Editable;
import android.text.Selection;
import android.view.KeyEvent;
import android.view.View;
import android.view.inputmethod.BaseInputConnection;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputMethodManager;
import com.unity.uiwidgets.plugin.UIWidgetsMessageManager;
import java.util.Arrays;
import java.util.HashMap;
class InputConnectionAdaptor extends BaseInputConnection {
private View mTextInputView;
private final int mClient;
private final Editable mEditable;
private int mBatchCount;
private InputMethodManager mImm;
public InputConnectionAdaptor(View view, int client,
Editable editable) {
super(view, true);
mTextInputView = view;
mClient = client;
mEditable = editable;
mBatchCount = 0;
mImm = (InputMethodManager) view.getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
}
// Send the current state of the editable to Flutter.
private void updateEditingState() {
// If the IME is in the middle of a batch edit, then wait until it completes.
if (mBatchCount > 0)
return;
int selectionStart = Selection.getSelectionStart(mEditable);
int selectionEnd = Selection.getSelectionEnd(mEditable);
int composingStart = BaseInputConnection.getComposingSpanStart(mEditable);
int composingEnd = BaseInputConnection.getComposingSpanEnd(mEditable);
mImm.updateSelection(mTextInputView,
selectionStart, selectionEnd,
composingStart, composingEnd);
HashMap<Object, Object> state = new HashMap<Object, Object>();
state.put("text", mEditable.toString());
state.put("selectionBase", selectionStart);
state.put("selectionExtent", selectionEnd);
state.put("composingBase", composingStart);
state.put("composingExtent", composingEnd);
UIWidgetsMessageManager.getInstance().UIWidgetsMethodMessage("TextInput", "TextInputClient.updateEditingState",
Arrays.asList(mClient, state));
}
@Override
public Editable getEditable() {
return mEditable;
}
@Override
public boolean beginBatchEdit() {
mBatchCount++;
return super.beginBatchEdit();
}
@Override
public boolean endBatchEdit() {
boolean result = super.endBatchEdit();
mBatchCount--;
updateEditingState();
return result;
}
@Override
public boolean commitText(CharSequence text, int newCursorPosition) {
boolean result = super.commitText(text, newCursorPosition);
updateEditingState();
return result;
}
@Override
public boolean deleteSurroundingText(int beforeLength, int afterLength) {
if (Selection.getSelectionStart(mEditable) == -1)
return true;
boolean result = super.deleteSurroundingText(beforeLength, afterLength);
updateEditingState();
return result;
}
@Override
public boolean setComposingRegion(int start, int end) {
boolean result = super.setComposingRegion(start, end);
updateEditingState();
return result;
}
@Override
public boolean setComposingText(CharSequence text, int newCursorPosition) {
boolean result;
if (text.length() == 0) {
result = super.commitText(text, newCursorPosition);
} else {
result = super.setComposingText(text, newCursorPosition);
}
updateEditingState();
return result;
}
@Override
public boolean setSelection(int start, int end) {
boolean result = super.setSelection(start, end);
updateEditingState();
return result;
}
@Override
public boolean sendKeyEvent(KeyEvent event) {
if (event.getAction() == KeyEvent.ACTION_DOWN) {
if (event.getKeyCode() == KeyEvent.KEYCODE_DEL) {
int selStart = Selection.getSelectionStart(mEditable);
int selEnd = Selection.getSelectionEnd(mEditable);
String text = mEditable.toString();
if(selStart >= 0 && selStart < text.length() && isTrailSurrogate(text.charAt(selStart))) {
selStart++;
}
if(selEnd >= 0 && selEnd < text.length() && isTrailSurrogate(text.charAt(selEnd))) {
selEnd++;
}
if (selEnd > selStart) {
// Delete the selection.
Selection.setSelection(mEditable, selStart);
mEditable.delete(selStart, selEnd);
updateEditingState();
return true;
} else if (selStart > 0) {
// Delete to the left of the cursor.
int newSel = Math.max(selStart - 1, 0);
if(selStart >= 2 && isTrailSurrogate(text.charAt(selStart-1)))
newSel = selStart - 2;
Selection.setSelection(mEditable, newSel);
mEditable.delete(newSel, selStart);
updateEditingState();
return true;
}
} else if (event.getKeyCode() == KeyEvent.KEYCODE_DPAD_LEFT) {
int selStart = Selection.getSelectionStart(mEditable);
int newSel = Math.max(selStart - 1, 0);
setSelection(newSel, newSel);
return true;
} else if (event.getKeyCode() == KeyEvent.KEYCODE_DPAD_RIGHT) {
int selStart = Selection.getSelectionStart(mEditable);
int newSel = Math.min(selStart + 1, mEditable.length());
setSelection(newSel, newSel);
return true;
} else {
// Enter a character.
int character = event.getUnicodeChar();
if (character != 0) {
int selStart = Math.max(0, Selection.getSelectionStart(mEditable));
int selEnd = Math.max(0, Selection.getSelectionEnd(mEditable));
if (selEnd != selStart)
mEditable.delete(selStart, selEnd);
mEditable.insert(selStart, String.valueOf((char) character));
setSelection(selStart + 1, selStart + 1);
updateEditingState();
}
return true;
}
}
return false;
}
@Override
public boolean performEditorAction(int actionCode) {
switch (actionCode) {
// TODO(mattcarroll): is newline an appropriate action for "none"?
case EditorInfo.IME_ACTION_NONE:
UIWidgetsMessageManager.getInstance().UIWidgetsMethodMessage("TextInput", "TextInputClient.performAction",
Arrays.asList(mClient, "TextInputAction.newline"));
break;
case EditorInfo.IME_ACTION_UNSPECIFIED:
UIWidgetsMessageManager.getInstance().UIWidgetsMethodMessage("TextInput", "TextInputClient.performAction",
Arrays.asList(mClient, "TextInputAction.unspecified"));
break;
case EditorInfo.IME_ACTION_GO:
UIWidgetsMessageManager.getInstance().UIWidgetsMethodMessage("TextInput", "TextInputClient.performAction",
Arrays.asList(mClient, "TextInputAction.go"));
break;
case EditorInfo.IME_ACTION_SEARCH:
UIWidgetsMessageManager.getInstance().UIWidgetsMethodMessage("TextInput", "TextInputClient.performAction",
Arrays.asList(mClient, "TextInputAction.search"));
break;
case EditorInfo.IME_ACTION_SEND:
UIWidgetsMessageManager.getInstance().UIWidgetsMethodMessage("TextInput", "TextInputClient.performAction",
Arrays.asList(mClient, "TextInputAction.send"));
break;
case EditorInfo.IME_ACTION_NEXT:
UIWidgetsMessageManager.getInstance().UIWidgetsMethodMessage("TextInput", "TextInputClient.performAction",
Arrays.asList(mClient, "TextInputAction.next"));
break;
case EditorInfo.IME_ACTION_PREVIOUS:
UIWidgetsMessageManager.getInstance().UIWidgetsMethodMessage("TextInput", "TextInputClient.performAction",
Arrays.asList(mClient, "TextInputAction.previous"));
break;
default:
case EditorInfo.IME_ACTION_DONE:
UIWidgetsMessageManager.getInstance().UIWidgetsMethodMessage("TextInput", "TextInputClient.performAction",
Arrays.asList(mClient, "TextInputAction.done"));
break;
}
return true;
}
private boolean isLeadSurrogate(int c) {
return (c & 0xfffffc00) == 0xd800;
}
private boolean isTrailSurrogate(int c) {
return (c & 0xfffffc00) == 0xdc00;
}
}

31
com.unity.uiwidgets/Runtime/Plugins/Android/InputConnectionAdaptor.java.meta


fileFormatVersion: 2
guid: ee71437b1f6244476b59360f556db8b7
PluginImporter:
externalObjects: {}
serializedVersion: 2
iconMap: {}
executionOrder: {}
defineConstraints: []
isPreloaded: 0
isOverridable: 1
isExplicitlyReferenced: 0
platformData:
- first:
Android: Android
second:
enabled: 1
settings: {}
- first:
Any:
second:
enabled: 0
settings: {}
- first:
Editor: Editor
second:
enabled: 0
settings:
DefaultValueInitialized: true
userData:
assetBundleName:
assetBundleVariant:

31
com.unity.uiwidgets/Runtime/Plugins/Android/TextInputPlugin.java.meta


fileFormatVersion: 2
guid: 867d39559763e4ea9b82b9a5987a1930
PluginImporter:
externalObjects: {}
serializedVersion: 2
iconMap: {}
executionOrder: {}
defineConstraints: []
isPreloaded: 0
isOverridable: 1
isExplicitlyReferenced: 0
platformData:
- first:
Android: Android
second:
enabled: 1
settings: {}
- first:
Any:
second:
enabled: 0
settings: {}
- first:
Editor: Editor
second:
enabled: 0
settings:
DefaultValueInitialized: true
userData:
assetBundleName:
assetBundleVariant:

48
com.unity.uiwidgets/Runtime/Plugins/Android/TextInputView.java


package com.unity.uiwidgets.plugin.editing;
import android.content.Context;
import android.util.Log;
import android.view.KeyCharacterMap;
import android.view.KeyEvent;
import android.view.View;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputConnection;
import android.view.inputmethod.InputMethodManager;
import org.json.JSONException;
import static com.unity.uiwidgets.plugin.Utils.TAG;
public class TextInputView extends View {
private InputConnection mLastInputConnection;
private final InputMethodManager mImm;
public TextInputView(Context context) {
super(context);
setFocusable(true);
setFocusableInTouchMode(true);
mImm = (InputMethodManager) getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
}
@Override
public InputConnection onCreateInputConnection(EditorInfo outAttrs) {
Log.i(TAG, "onCreateInputConnection");
try {
mLastInputConnection = TextInputPlugin.getInstance().createInputConnection(this, outAttrs);
return mLastInputConnection;
} catch (JSONException e) {
Log.e(TAG, "Failed to create input connection", e);
return null;
}
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (event.getDeviceId() != KeyCharacterMap.VIRTUAL_KEYBOARD) {
if (mLastInputConnection != null && mImm.isAcceptingText()) {
mLastInputConnection.sendKeyEvent(event);
}
}
return super.onKeyDown(keyCode, event);
}
}

31
com.unity.uiwidgets/Runtime/Plugins/Android/TextInputView.java.meta


fileFormatVersion: 2
guid: acd0b1bb7c09d4b5ca41554aa9c30257
PluginImporter:
externalObjects: {}
serializedVersion: 2
iconMap: {}
executionOrder: {}
defineConstraints: []
isPreloaded: 0
isOverridable: 1
isExplicitlyReferenced: 0
platformData:
- first:
Android: Android
second:
enabled: 1
settings: {}
- first:
Any:
second:
enabled: 0
settings: {}
- first:
Editor: Editor
second:
enabled: 0
settings:
DefaultValueInitialized: true
userData:
assetBundleName:
assetBundleVariant:

254
com.unity.uiwidgets/Runtime/Plugins/Android/TextInputPlugin.java


package com.unity.uiwidgets.plugin.editing;
import android.content.Context;
import android.text.Editable;
import android.text.InputType;
import android.text.Selection;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import android.view.inputmethod.BaseInputConnection;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputConnection;
import android.view.inputmethod.InputMethodManager;
import com.unity3d.player.UnityPlayer;
import org.json.JSONException;
import org.json.JSONObject;
import static com.unity.uiwidgets.plugin.Utils.TAG;
public class TextInputPlugin {
private final TextInputView mView;
private final InputMethodManager mImm;
private int mClient = 0;
private JSONObject mConfiguration;
private Editable mEditable;
private boolean mRestartInputPending;
private static TextInputPlugin _instance;
public static TextInputPlugin getInstance() {
if (_instance == null) {
_instance = new TextInputPlugin();
}
return _instance;
}
public TextInputPlugin() {
ViewGroup contentView = (ViewGroup)UnityPlayer.currentActivity.findViewById(android.R.id.content);
mView = new TextInputView(UnityPlayer.currentActivity);
mView.requestFocus();
contentView.addView(mView, 1, 1);
mImm = (InputMethodManager) mView.getContext().getSystemService(
Context.INPUT_METHOD_SERVICE);
}
public static void show() {
UnityPlayer.currentActivity.runOnUiThread(new Runnable() {
@Override
public void run() {
TextInputPlugin plugin = getInstance();
plugin.showTextInput(plugin.mView);
}
});
}
public static void hide() {
UnityPlayer.currentActivity.runOnUiThread(new Runnable() {
@Override
public void run() {
TextInputPlugin plugin = getInstance();
plugin.hideTextInput(plugin.mView);
}
});
}
public static void setClient(int client, String configurationJson) {
UnityPlayer.currentActivity.runOnUiThread(new Runnable() {
@Override
public void run() {
try {
JSONObject configuration = new JSONObject(configurationJson);
TextInputPlugin plugin = getInstance();
plugin.setTextInputClient(plugin.mView, client, configuration);
} catch (JSONException e) {
Log.e(TAG, "error parse json", e);
}
}
});
}
public static void setEditingState(String stateJson) {
UnityPlayer.currentActivity.runOnUiThread(new Runnable() {
@Override
public void run() {
try {
TextInputPlugin plugin = getInstance();
JSONObject state = new JSONObject(stateJson);
plugin.setTextInputEditingState(plugin.mView, state);
} catch (JSONException e) {
Log.e(TAG, "error parse json", e);
}
}
});
}
public static void clearClient() {
UnityPlayer.currentActivity.runOnUiThread(new Runnable() {
@Override
public void run() {
TextInputPlugin plugin = getInstance();
plugin.clearTextInputClient();
}
});
}
private static int inputTypeFromTextInputType(JSONObject type, boolean obscureText,
boolean autocorrect, String textCapitalization) throws JSONException {
String inputType = type.getString("name");
if (inputType.equals("TextInputType.datetime")) return InputType.TYPE_CLASS_DATETIME;
if (inputType.equals("TextInputType.number")) {
int textType = InputType.TYPE_CLASS_NUMBER;
if (type.optBoolean("signed")) textType |= InputType.TYPE_NUMBER_FLAG_SIGNED;
if (type.optBoolean("decimal")) textType |= InputType.TYPE_NUMBER_FLAG_DECIMAL;
return textType;
}
if (inputType.equals("TextInputType.phone")) return InputType.TYPE_CLASS_PHONE;
int textType = InputType.TYPE_CLASS_TEXT;
if (inputType.equals("TextInputType.multiline"))
textType |= InputType.TYPE_TEXT_FLAG_MULTI_LINE;
else if (inputType.equals("TextInputType.emailAddress"))
textType |= InputType.TYPE_TEXT_VARIATION_EMAIL_ADDRESS;
else if (inputType.equals("TextInputType.url"))
textType |= InputType.TYPE_TEXT_VARIATION_URI;
if (obscureText) {
// Note: both required. Some devices ignore TYPE_TEXT_FLAG_NO_SUGGESTIONS.
textType |= InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS;
textType |= InputType.TYPE_TEXT_VARIATION_PASSWORD;
} else {
if (autocorrect) textType |= InputType.TYPE_TEXT_FLAG_AUTO_CORRECT;
}
if (textCapitalization.equals("TextCapitalization.characters")) {
textType |= InputType.TYPE_TEXT_FLAG_CAP_CHARACTERS;
} else if (textCapitalization.equals("TextCapitalization.words")) {
textType |= InputType.TYPE_TEXT_FLAG_CAP_WORDS;
} else if (textCapitalization.equals("TextCapitalization.sentences")) {
textType |= InputType.TYPE_TEXT_FLAG_CAP_SENTENCES;
}
return textType;
}
private static int inputActionFromTextInputAction(String inputAction) {
switch (inputAction) {
case "TextInputAction.newline":
return EditorInfo.IME_ACTION_NONE;
case "TextInputAction.none":
return EditorInfo.IME_ACTION_NONE;
case "TextInputAction.unspecified":
return EditorInfo.IME_ACTION_UNSPECIFIED;
case "TextInputAction.done":
return EditorInfo.IME_ACTION_DONE;
case "TextInputAction.go":
return EditorInfo.IME_ACTION_GO;
case "TextInputAction.search":
return EditorInfo.IME_ACTION_SEARCH;
case "TextInputAction.send":
return EditorInfo.IME_ACTION_SEND;
case "TextInputAction.next":
return EditorInfo.IME_ACTION_NEXT;
case "TextInputAction.previous":
return EditorInfo.IME_ACTION_PREVIOUS;
default:
// Present default key if bad input type is given.
return EditorInfo.IME_ACTION_UNSPECIFIED;
}
}
public InputConnection createInputConnection(View view, EditorInfo outAttrs)
throws JSONException {
if (mClient == 0) return null;
outAttrs.inputType = inputTypeFromTextInputType(mConfiguration.getJSONObject("inputType"),
mConfiguration.optBoolean("obscureText"),
mConfiguration.optBoolean("autocorrect", true),
mConfiguration.getString("textCapitalization"));
outAttrs.imeOptions = EditorInfo.IME_FLAG_NO_FULLSCREEN;
int enterAction;
if (mConfiguration.isNull("inputAction")) {
// If an explicit input action isn't set, then default to none for multi-line fields
// and done for single line fields.
enterAction = (InputType.TYPE_TEXT_FLAG_MULTI_LINE & outAttrs.inputType) != 0
? EditorInfo.IME_ACTION_NONE
: EditorInfo.IME_ACTION_DONE;
} else {
enterAction = inputActionFromTextInputAction(mConfiguration.getString("inputAction"));
}
if (!mConfiguration.isNull("actionLabel")) {
outAttrs.actionLabel = mConfiguration.getString("actionLabel");
outAttrs.actionId = enterAction;
}
outAttrs.imeOptions |= enterAction;
InputConnectionAdaptor connection =
new InputConnectionAdaptor(view, mClient, mEditable);
outAttrs.initialSelStart = Selection.getSelectionStart(mEditable);
outAttrs.initialSelEnd = Selection.getSelectionEnd(mEditable);
return connection;
}
private void showTextInput(View view) {
view.requestFocus();
mImm.showSoftInput(view, 0);
}
private void hideTextInput(View view) {
mImm.hideSoftInputFromWindow(view.getApplicationWindowToken(), 0);
}
private void setTextInputClient(View view, int client, JSONObject configuration) {
mClient = client;
mConfiguration = configuration;
mEditable = Editable.Factory.getInstance().newEditable("");
// setTextInputClient will be followed by a call to setTextInputEditingState.
// Do a restartInput at that time.
mRestartInputPending = true;
}
private void applyStateToSelection(JSONObject state) throws JSONException {
int selStart = state.getInt("selectionBase");
int selEnd = state.getInt("selectionExtent");
if (selStart >= 0 && selStart <= mEditable.length() && selEnd >= 0
&& selEnd <= mEditable.length()) {
Selection.setSelection(mEditable, selStart, selEnd);
} else {
Selection.removeSelection(mEditable);
}
}
private void setTextInputEditingState(View view, JSONObject state) throws JSONException {
if (!mRestartInputPending && state.getString("text").equals(mEditable.toString())) {
applyStateToSelection(state);
mImm.updateSelection(mView, Math.max(Selection.getSelectionStart(mEditable), 0),
Math.max(Selection.getSelectionEnd(mEditable), 0),
BaseInputConnection.getComposingSpanStart(mEditable),
BaseInputConnection.getComposingSpanEnd(mEditable));
} else {
mEditable.replace(0, mEditable.length(), state.getString("text"));
applyStateToSelection(state);
mImm.restartInput(view);
mRestartInputPending = false;
}
}
private void clearTextInputClient() {
mClient = 0;
}
}
正在加载...
取消
保存