Giter Club home page Giter Club logo

engine's Introduction

Flutter for Tizen

Test

An extension to the Flutter SDK for building Flutter applications for Tizen devices.

Flutter and the related logo are trademarks of Google LLC. This project is sponsored and maintained by Samsung Research.

Supported devices

Installation

Usage

flutter-tizen substitutes the original flutter CLI command. Only the command line interface is supported.

# Inspect the installed tooling and list all connected devices.
flutter-tizen doctor -v
flutter-tizen devices

# Set up a new app project, or add Tizen files if the project already exists.
flutter-tizen create myapp
cd myapp

# Build the project and run on a Tizen device (either in debug or release mode).
flutter-tizen run
flutter-tizen run --release
  • See Supported commands for all available commands and their basic usage. See [command] -h for more information on each command.
  • See Getting started to create your first app and try hot reload.
  • To update the flutter-tizen tool, run git pull in this directory.

Docs

Tizen basics

App development

Platform integration

Miscellaneous

Issues

If you run into any problem, post an issue in this repository to get help. If your issue is clearly not Tizen-specific (i.e. it's reproducible with the regular flutter command), you may file an issue in https://github.com/flutter/flutter/issues.

Contribution

This project is community-driven and we welcome all your contributions and feedback. Consider filing an issue or pull request to make this project better.

engine's People

Contributors

aam avatar abarth avatar bdero avatar bkonyi avatar cbracken avatar chinmaygarde avatar collinjackson avatar dnfield avatar esprehn avatar ferhatb avatar flar avatar gaaclarke avatar garyqian avatar goderbauer avatar godofredoc avatar hixie avatar iskakaushik avatar jason-simmons avatar johnmccutchan avatar jonahwilliams avatar liyuqian avatar matanlurey avatar mdebbar avatar ojanvafai avatar raphlinus avatar skia-flutter-autoroll avatar stuartmorgan avatar vlidholt avatar yjbanov avatar zanderso avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

engine's Issues

Improve the engine CI

Build

  • Build for each arch/mode/profile

Analyze

  • Formatting & Linter โ†’ #90
  • API checker (ensure no internal API is used by the wearable embedder) โ†’ #140

Release

  • Automatic release (the GitHub Release task didn't work when I tested last time ๐Ÿค”)
  • File server for hosting releases (we need our own domain)
  • Admin dashboard (to check the number of downloads for each release, etc.)

Test

  • (meta) Add a self-hosted instance to the Pipelines (pricing: $15/month) to run tests on a local machine
  • Run integration tests (run sample apps on a set of test devices and check if they behave correctly)
  • Run regression tests (measure the performance of sample apps and compare with the previous results)
  • Add unit tests for the Tizen embedder and run

Support to get native window

when I implement presentation displays plugin, engine should provide interface for getting elm window.
I think other plugins may also need this interface in the future.

Issues(Get ecore_wl2_window from elm window)

  • Rotation .
  • Create egl window fail on RPI.
  • Black screen when launch app.

Flutter 2.8 crashes with SIGSEGV in release mode

A segmentation fault occurs only in release mode:

* thread #25, name = 'io.flutter.ui', stop reason = signal SIGSEGV: invalid address (fault address: 0x8)
  * frame #0: 0xe16a43e4
    frame #1: 0xe16bc050
    frame #2: 0xe17001d4
    frame #3: 0xe16ff3c0
    frame #4: 0xe16ff250
    frame #5: 0xe16ff03c
    frame #6: 0xe16fef10
    frame #7: 0xe1770adc
    frame #8: 0xe17709e0
    frame #9: 0xe17709b8
    frame #10: 0xe183b1a0
    frame #11: 0xe183b1cc
    frame #12: 0xe183d138
    frame #13: 0xe16c6430
    frame #14: 0xe16765d4
    frame #15: 0xe16766b4
    frame #16: 0xe18180f0
    frame #17: 0xe1677454
    frame #18: 0xe1679058
    frame #19: 0xe16c6264
    frame #20: 0xe183d7f0
    frame #21: 0xe167e288
    frame #22: 0xe183d138
    frame #23: 0xe167c80c
    frame #24: 0xe166eaa4
    frame #25: 0xe3a27216 libflutter_engine.so`dart::DartEntry::InvokeCode(code=<unavailable>, entry_point=<unavailable>, arguments_descriptor=<unavailable>, arguments=<unavailable>, thread=<unavailable>) at dart_entry.cc:0
    frame #26: 0xe183afb4

How to reproduce:

  1. Fetch flutter-tizen/flutter-tizen#287.
  2. Run TIZEN_ENGINE_AZURE_BUILD_ID=699 flutter-tizen precache --tizen.
  3. Run any Flutter app in release mode on any of your devices (arm or arm64).

Not sure how to debug because the crash occurs in the UI thread (Dart code), but maybe we can try reverting the Dart runtime version or running an asan build of the engine.

[Tizen 5.5 watch] Apps cannot launch in candidate mode

.NET type apps crash on my Tizen 5.5 watch device when run in candidate mode (launched from an existing loader process without creating a new process). The issue is probably related to the EFL preloading feature on watch devices. (Removing files in /usr/share/dotnet.tizen/preload temporarily fixes the problem - only for rooted devices.)

How to reproduce:

  1. Create a project and run on a 5.5 watch device:

    flutter-tizen create --tizen-language csharp .
    flutter-tizen run
    
    The app is run in standalone mode when it's launched for the first time after install.
  2. Stop the app.
  3. Wait for 5 seconds (until a loader process starts) and launch the app again, by clicking an app icon or using app_launcher -s.

lldb caught a segmentation fault at libfreetype.so code section:

(lldb) Process 7461 stopped
* thread #21, name = 'io.flutter.ui', stop reason = signal SIGSEGV: invalid address (fault address: 0x30)
    frame #0: 0xec19e0e6 libfreetype.so.6
->  0xec19e0e6: .long  0xb1036b1b                ; unknown opcode
    0xec19e0ea: addshs r4, r6, r8, lsl r7
    0xec19e0ee: .long  0xf8d04770                ; unknown opcode
    0xec19e0f2: push   {r2, r3, r8, r9, r12, sp}
bt
* thread #21, name = 'io.flutter.ui', stop reason = signal SIGSEGV: invalid address (fault address: 0x30)
  * frame #0: 0xec19e0e6 libfreetype.so.6
    frame #1: 0xe4a7e03a libflutter_engine.so

Device info:

bash-3.2# cat /etc/os-release
NAME=Tizen
VERSION="5.5.0 (Tizen5/Unified)"
ID=tizen
VERSION_ID=5.5.0
PRETTY_NAME="Tizen 5.5.0 (Tizen5/Unified)"
ANSI_COLOR="0;36"
CPE_NAME="cpe:/o:tizen:tizen:5.5.0"
BUILD_ID=PLATFORM_DayR800XX_20200611.001

The issue doesn't occur on Tizen 6.0 devices because:

  • The system freetype library version is newer.
  • Apps launch in standalone mode only, because the http://tizen.org/metadata/direct-launch metadata value is by default enabled in tizen-manifest.xml. The metadata was first introduced in Tizen 6.0.

Embedder without EFL

I'm currently writing an experimental embedder that purely depends on wayland so that it can work with other compositors (more specifically Weston) than Enlightenment. I'm not sure if the work will go very well. I'll make updates here when some progress is made.

If anybody is familiar with this topic or has ever considered about the approach, please share your thoughts.

Support multiple screens

Background?

There are requirements for multiple screens. There's nothing specific, everything can change, but multiple screens don't change. ๐Ÿ˜„ So I checked how multi-screen support is going on in Flutter. And I found the following:

https://docs.google.com/document/d/11_4wntz_9IJTQOo_Qhp7QF4RfpIMTfVygtOTxQ4OGHY/edit
https://github.com/flutter/flutter/issues/30701
https://github.com/google/flutter-desktop-embedding/issues/98

IMO, Supporting multiple windows didn't seem to happen soon at this moment. So I decided to look for Plan B.
That is EngineGroup feature.(https://flutter.dev/docs/development/add-to-app/multiple-flutters)
Technically, Itโ€™s a little different but I thought It would be able to produce similar looking with multi screen app.
So, I aimed the first step of this task to port sample app(https://github.com/flutter/samples/tree/master/add_to_app/multiple_flutters) at tizen.


EngineGroup

As you can see in the example, this is part of how to embed Flutter in a native app. The best way is to embed Flutter in tizen as one of the GUI widgets , but this is not easy In the current implementation. (Many of our rendering behavior are
based on window)
Here is my rough plan based on these.

  1. Make windows externally and use them. This will allow us to create and place partial windows at single app. (#98)
  2. Create spawn API in embedder.
  3. Create FlutterEngineGroup API at native API
  4. Port sample app to tizen

(Of course, I am not insisting that this feature should be done this way. Any ideas are welcome. ๐Ÿ˜„ )

Return Image handle instead of window (EFL)

Nice to meet you devs. I'm studying flutter and have a question, so I'm making a sample and writing my opinion here :)

Currently, AddtoApp of flutter-tizen can be implemented by using a window handle. (ecore_wl2, elm_win)

To add the rendered flutter output to the elementary widget, it was not appropriate to use elm_win.
(I tried using other types of windows, but it didn't work as intended. (ELM_WIN_INLINED_IMAGE type of elm_win))

I made a sample by modifying the evas_gl.cc code to use the evas image handle.
The user can get the image handle after set the parent window or parent widget appropriately. And they can add it somewhere.

Below is a sample of this idea.
If a suitable interface and sample code to add parent are presented, users can expect to output FlutterView(?) in EFL-based apps.
(Of course, this is not a nice interface unless multi-instance (maybe FlutterGroup?) is applied.)

sample)
sample

https://github.com/JSUYA/engine/tree/jsuya/flutter-2.8.1-tizen/dev/evas_image

[Tizen 4.0] Apps cannot launch

Apps cannot be started on a Tizen 4.0 device/emulator (regardless of the build mode or app type) after Flutter 2.0 update. Wanchao has initially reported this issue by testing on a Tizen 4.0 watch emulator (with a plugin sample) and the issue has been confirmed to be applicable for any Tizen 4.0 device and any app.

Launching lib/main.dart on Tizen TM1 in debug mode...
The Platform profile is used for signing.
Building a Tizen application in debug mode...                      25.3s
โœ“ Built build/tizen/com.example.csharp-1.0.0.tpk (22.7MB).
Installing build/tizen/com.example.csharp-1.0.0.tpk...             23.3s
I/ConsoleMessage(30212): FlutterApplication.cs: OnCreate(54) > switches: --enable-dart-profiling --enable-checked-mode
W/ConsoleMessage(30212): ../../../../flutter/shell/platform/tizen/tizen_renderer.cc: OnProcResolver(204) > Could not resolve: glGetStringi
W/ConsoleMessage(30212): ../../../../flutter/shell/platform/tizen/tizen_renderer.cc: OnProcResolver(204) > Could not resolve: glGetStringi
E/ConsoleMessage(30212): ../../../../flutter/shell/platform/tizen/flutter_tizen.cc: FlutterDesktopRegistrarGetTextureRegistrar(221) > Tizen DesktopTexture support is not implemented yet.
Activating Dart DevTools...                                         3.4s

Support dart entrypoint

Typically, a Flutter app begins execution at the Dart method called main(), however this is not required. Developers can specify a different Dart entrypoint

Invalid name of a privilege in a log message

The problem was reported in flutter-tizen/plugins#115 (comment):

By the way it looks like the required privilege is http://tizen.org/privilege/haptic but not http://tizen.org/privilege/feedback. @pwasowski2 We need to update this error message at some time.

E/ConsoleMessage( 3898): platform_channel.cc: Play(129) > feedback_play_type() failed with error: [-13] (Permission denied)
E/ConsoleMessage( 3898): platform_channel.cc: HandleMethodCall(244) > No permission to run HapticFeedback.lightImpact(). Add "http://tizen.org/privilege/feedback" privilege to tizen-manifest.xml to use this method: Could not vibrate
E/ConsoleMessage( 3898): [ERROR:flutter/lib/ui/ui_dart_state.cc(186)] Unhandled Exception: PlatformException(No permission 

Fix: #109

Font not rendering in some cases

Font not rendering issues were noticed in:

Even with some patches, the problem is not fully fixed. I tried to solve the problem, but I'm kind of stuck. I hope someone could give me some advice. Or, you could try to fix it if you're interested.

Using fontconfig

Problem: Using fontconfig matches wrong font style for English language on wearable devices.

On wearable devices, English text is matched to some other language font that doesn't contain glyphs for Latin characters. Skia doesn't get the font information from running fontconfig executables, it uses fontconfig apis to parse the configuration file itself. The problem happens only when system font is set to "default"(SamsungOneUI).

Fontconfig configuration file is in read-only file system: /etc/fonts, so maybe I shouldn't be changing this file directly, but change the skia code that parses it?

Wearable device:

# English text should be matched to "SamsungOneUI", but it gets matched to some other font in this list:

Fonts selected by "SamsungOneUI", 15 styles selected.
I/ConsoleMessage( 2451): family name for font is...: BreezeSansMyanmar
I/ConsoleMessage( 2451): family name for font is...: SamsungOneUISCN
I/ConsoleMessage( 2451): family name for font is...: BreezeColorEmoji
I/ConsoleMessage( 2451): family name for font is...: SamsungOneUIEthiopic
I/ConsoleMessage( 2451): family name for font is...: BreezeSansGeorgian
I/ConsoleMessage( 2451): family name for font is...: BreezeSansJapanese
I/ConsoleMessage( 2451): family name for font is...: BreezeSansKhmer
I/ConsoleMessage( 2451): family name for font is...: SamsungOneUITCN
I/ConsoleMessage( 2451): family name for font is...: SECEmoji
I/ConsoleMessage( 2451): family name for font is...: SamsungOneUIEthiopic
I/ConsoleMessage( 2451): family name for font is...: BreezeSansGeorgian
I/ConsoleMessage( 2451): family name for font is...: SamsungOneUIKorean
I/ConsoleMessage( 2451): family name for font is...: SamsungOneUI
I/ConsoleMessage( 2451): family name for font is...: SamsungOneUIKorean
I/ConsoleMessage( 2451): family name for font is...: SamsungOneUI

image
image

On other targets, it works fine.

TV device:

image

Mobile device:

image

Wearable emulator:

image
image

TV emulator:

image

Mobile emulator:

image

Not using fontconfig

If we don't use fontconfig(the current engine build), characters that use custom fonts can't use system fallback fonts if those characters don't have matching glyphs in the custom font files.

Wearable device:

image
image

TV device:

For some reason, the TV device I have can't run the app at the moment.

mobile device:

image

Wearable emulator:

image
image

TV emulator:

image

Mobile emulator:

image

Let me know if you need more details, or want to test with the app in the image.

Some unresolved issues

Similarly to flutter-tizen/flutter-tizen#60, here are some works to be done for the engine and our embedder. Please open a dedicated issue or PR if you are interested with any.

  • Alternative logging method on TVs (avoid using __dlog_print) โ†’ #67
  • Advanced continuous integration โ†’ Addressed by #89
  • Non-fatal error "xkbcommon: ERROR: couldn't find a Compose file for locale" on app launch (unrelated to Flutter) โ†’ #91
  • Endless thread creation on watch devices ("Thread added to display, Thread removed to display, ...") โ†’ Not reproducible
  • Implement platform channel methods (setPreferredOrientations, vibrate, Clipboard.*, play) โ†’ #65, #75, #79, #84
  • Analyze performance issues (gallery app is sluggish, frame janks)
  • Investigate why SkSL shaders cannot be collected on Tizen devices โ†’ #55
  • Symbol resolution fails for system libraries in DevTools stack traces โ†’ #95
  • Cupertino widget animation flickering issue on TM1 devices โ†’ flutter-tizen/embedder#5
  • Enable arm64 engine builds โ†’ #63
  • Remove Tizen-specific texture APIs โ†’ #82
  • Overall refactoring โ†’ WIP

Refactor getting values from EncodableMap to use common template

https://github.com/rwalczyna/engine/blob/app_control/shell/platform/tizen/channels/app_control_channel.cc#L144

It has the same purpose as GetValueFromEncodeableMap in platform_view_channel.cc
I'd like to ask for a little refactoring so that all tizen channels can use this template in common.

bool GetValueFromEncodableMap(const EncodableValue& arguments,

Originally posted by @bbrto21 in #154 (comment)

[Key mapping issue]Exception was thrown by flutter framework when press 'Menu' key on TV device

โ•โ•โ•ก EXCEPTION CAUGHT BY SERVICES LIBRARY โ•žโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
The following assertion was thrown during a platform message callback:
Attempted to send a key down event when no keys are in keysPressed. This state can occur if the key
event being sent doesn't properly set its modifier flags. This was the event:
RawKeyDownEvent#80af0(logicalKey: LogicalKeyboardKey#00106(keyId: "0x200000106", keyLabel: "Meta
Left", debugName: "Meta Left"), physicalKey: PhysicalKeyboardKey#700e3(usbHidUsage: "0x000700e3",
debugName: "Meta Left")) and its data: RawKeyEventDataLinux#ef142(toolkit: GTK, unicodeScalarValues:
0, scanCode: 133, keyCode: 65511, modifiers: 0, isDown: true)
'package:flutter/src/services/raw_keyboard.dart':
Failed assertion: line 694 pos 7: 'event is! RawKeyDownEvent || _keysPressed.isNotEmpty'

Either the assertion indicates an error in the framework itself, or we should provide substantially
more information in this error message to help you determine and fix the underlying cause.
In either case, please report this assertion by filing a bug on GitHub:
https://github.com/flutter/flutter/issues/new?template=2_bug.md

When the exception was thrown, this was the stack:
#2 RawKeyboard.handleRawKeyEvent (package:flutter/src/services/raw_keyboard.dart:694:7)
#3 KeyEventManager.handleRawKeyMessage (package:flutter/src/services/hardware_keyboard.dart:818:33)
#4 BasicMessageChannel.setMessageHandler. (package:flutter/src/services/platform_channel.dart:77:49)
#5 BasicMessageChannel.setMessageHandler. (package:flutter/src/services/platform_channel.dart:76:47)
#6 _DefaultBinaryMessenger.setMessageHandler. (package:flutter/src/services/binding.dart:389:35)
#7 _DefaultBinaryMessenger.setMessageHandler. (package:flutter/src/services/binding.dart:386:46)
#8 _invoke2. (dart:ui/hooks.dart:189:15)
#12 _invoke2 (dart:ui/hooks.dart:188:10)
#13 _ChannelCallbackRecord.invoke (dart:ui/channel_buffers.dart:42:5)
#14 _Channel.push (dart:ui/channel_buffers.dart:132:31)
#15 ChannelBuffers.push (dart:ui/channel_buffers.dart:329:17)
#16 PlatformDispatcher._dispatchPlatformMessage (dart:ui/platform_dispatcher.dart:544:22)
#17 _dispatchPlatformMessage (dart:ui/hooks.dart:83:31)
(elided 5 frames from class _AssertionError and dart:async)
โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•

Blank screen is displayed when launching app on Evas GL

Originally posted at : flutter-tizen/plugins#266 by @swift-kim

Even without splash screen, when launching app newly on wearable, a blank screen is displayed once for a while.
If you set elm_win_alpha_set as a true, it may seem to be solved, but it is not right to always treat it as transparent(This may affect performance badly).

Related discussions

Better support for building system-ui apps

I'm still surveying about the subject. This issue is to share and discuss what I'm currently looking into.

System UI is an application that runs when a device is powered on. It keeps track and provides control to system-wide setting, status, notification, etc. Examples: lockscreen UI, navigation bar, notification app, status bar, volume UI, ...

I'm posting a youtube link, What's new in System UI, so that you can get a sense on what a system ui might be in Android.

I'm looking into the following subjects in consideration of some performance metrics such as start-up time, response time, and memory consumption:

Symbol resolution fails for system libraries in DevTools stack traces in Performance tab

The problem is described in: #53 (comment)

run an app in profile mode and open the Performance view in Flutter DevTools, you will see this screen:

DevTools view

As you can see in the stack traces at the bottom of the view (CPU Flame Chart), symbols are resolved to their offsets within the shared objects (/proc/self/fd/35/lib/libflutter_engine.so+0x.....) but not their actual names. I'm not sure whether this is normal (because the symbols were stripped out).

Investigate the advantage of enabling SkSL warmup

What is shader compilation jank?

https://flutter.dev/docs/perf/rendering/shader

How to enable SkSL warm-up on Tizen?

  1. Set the FlutterProjectArgs.persistent_cache_path value to either a system temp directory or the app cache directory before starting the engine. Alternatively, the cache directory can be set by implementing fml::paths::GetCachesDirectory() in fml/platform/linux/paths_linux.cc (not tested). Shaders will be stored to this directory on the first run of an app, and the cached shaders will be used on subsequent runs.

  2. You can optionally bundle the shaders with a tpk (as a json file in res/flutter_assets) to accelerate the first run of the app on other devices: https://flutter.dev/docs/perf/rendering/shader#how-to-use-sksl-warmup

Pros and cons

  • Reduced shader compilation janks (not confirmed on Tizen - how can we measure this accurately?)
  • Increased app startup latency because cached/bundled shaders need to be precompiled
  • Slightly larger app size due to bundled shaders

Read more

[VD]TV์˜ ๋ฆฌ๋ชจ์ปจ ํ‚ค๊ฐ’ ๊ด€๋ จ ๋ฌธ์˜

์•ˆ๋…•ํ•˜์„ธ์š”.

ํ‚ค๋ณด๋“œ ๋ฐ ๋ฆฌ๋ชจ์ปจ ์—์„œ ๋ฐœ์ƒํ•˜๋Š” ํ‚ค๊ฐ’์— ๋Œ€ํ•ด ์•„๋ž˜ URL๋‚ด์— ์žˆ๋Š” sample์„ ํ†ตํ•ด ๋ฐœ์ƒ๋˜๋Š” ๋ช‡๊ฐ€์ง€ ํ‚ค๋ฅผ ํ™•์ธํ•ด ๋ดค์Šต๋‹ˆ๋‹ค.
https://api.flutter.dev/flutter/services/LogicalKeyboardKey-class.htm

๋ฆฌ๋ชจ์ปจ์˜ ์ƒํ•˜์ขŒ์šฐ ํ‚ค๋Š” Arrow Up, Down, Left, Right๋กœ logicalKey, pysicalKey์— ๋งค์นญ์ด ์ž˜๋˜์–ด ์žˆ๋Š” ๊ฒƒ์„ ํ™•์ธํ–ˆ๊ณ 
X86AudioPlay์˜ ๊ฒฝ์šฐ ํ‚ค๋ณด๋“œ๋กœ ๋งค์นญ๋˜๋Š” ๊ฐ’์ด ์—†์–ด์„œ "Media Play"๋กœ ์‹ ๊ทœ๋กœ ์ •์˜ ๋œ ๊ฒƒ๋„ ํ™•์ธํ–ˆ์Šต๋‹ˆ๋‹ค.

์ด์™ธ์— ์ฑ„๋„ ์—…/๋‹ค์šด/Mute, Red, Blue,Green๊ณผ ๊ฐ™์€ ํ‚ค๋Š” F1~12์‚ฌ์ด์˜ functionํ‚ค๋กœ ๋งค์นญ์ด ๋˜๋Š” ๊ฒƒ์œผ๋กœ ํ™•์ธ์ด ๋˜๋Š”๋ฐ์š”.
์ด๊ฒƒ์€ ์–ด๋–ค ๊ธฐ์ค€์œผ๋กœ ์ด๋ ‡๊ฒŒ ๋งค์นญ์ด ๋๋Š”์ง€ ์ž˜ ๋ชจ๋ฅด๊ฒ ๋„ค์š”.

์ง€์›๋˜๋Š” ๋ฆฌ๋ชจ์ปจ ํ‚ค๊ฐ€ ์•„๋ž˜์™€ ๊ฐ™์ด ๋‹ค์ˆ˜ ์žˆ๋Š”๋ฐ์š”.
์ด ๊ฐ’๋“ค์ด logicalKey, pysicalKey์—์„œ ์–ด๋–ค ๊ฐ’์œผ๋กœ ์ „๋‹ฌ ๋˜๋Š”์ง€ ์ •๋ฆฌ๋œ ์ž๋ฃŒ๊ฐ€ ์žˆ์œผ์‹œ๋ฉด ๊ณต์œ  ๋ถ€ํƒ ๋“œ๋ฆฝ๋‹ˆ๋‹ค.

https://github.com/flutter-tizen/engine/blob/flutter-2.10.1-tizen/shell/platform/tizen/key_event_handler.cc
const std::vectorstd::string kBindableSystemKeys = {
"XF86Menu", "XF86Back", "XF86AudioPlay",
"XF86AudioPause", "XF86AudioStop", "XF86AudioNext",
"XF86AudioPrev", "XF86AudioRewind", "XF86AudioForward",
"XF86AudioPlayPause", "XF86AudioRecord", "XF86LowerChannel",
"XF86RaiseChannel", "XF86ChannelList", "XF86PreviousChannel",
"XF86SysMenu", "XF86SimpleMenu", "XF86History",
"XF86Favorites", "XF86Info", "XF86Red",
"XF86Green", "XF86Yellow", "XF86Blue",
"XF86Subtitle", "XF86PlayBack", "XF86ChannelGuide",
"XF86Caption", "XF86Exit",
};

http://wiki.vd.sec.samsung.net/pages/viewpage.action?pageId=174034907 ๋‚ด์˜ ๊ทธ๋ฆผ ์ฐธ๊ณ 

Separate debug info files from unstripped binaries

Currently it's not possible to do source line-level debugging of the engine and embedder binaries (even with so.unstripped binaries) because the compiler strips out all debugging information (-g0) by default:

Extracting debug info files from unstripped binaries (and publishing them along with engine releases) will make it convenient to debug the engine and embedder via gdb and gdbserver.

(before)

(gdb) bt
#0  0xb4d67ea5 in system_info_get_platform_string () from target:/lib/libcapi-system-info.so.0
#1  0xb737e077 in (anonymous namespace)::NativePlugin::HandleMethodCall (this=0x803374a0, method_call=..., result=...) at src/native_plugin_plugin.cc:48
#2  0xb737df1d in (anonymous namespace)::NativePlugin::RegisterWithRegistrar(flutter::PluginRegistrar*)::{lambda(auto:1 const&, auto:2)#1}::operator()<flutter::MethodCall<flutter::EncodableValue>, std::unique_ptr<flutter::MethodResult<flutter::MethodCall>, std::default_delete<flutter::MethodResult> > >(flutter::MethodCall<flutter::EncodableValue> const&, std::unique_ptr<flutter::MethodResult<flutter::MethodCall>, std::default_delete<flutter::MethodResult> >) const (this=0x8036f450, call=..., result=...) at src/native_plugin_plugin.cc:29
#3  0xb737dce6 in std::_Function_handler<void (flutter::MethodCall<flutter::EncodableValue> const&, std::unique_ptr<flutter::MethodResult<flutter::EncodableValue>, std::default_delete<flutter::MethodResult<flutter::EncodableValue> > >), (anonymous namespace)::NativePlugin::RegisterWithRegistrar(flutter::PluginRegistrar*)::{lambda(auto:1 const&, auto:2)#1}>::_M_invoke(std::_Any_data const&, flutter::MethodCall<flutter::EncodableValue> const&, std::unique_ptr<flutter::MethodResult<flutter::EncodableValue>, std::default_delete<flutter::MethodResult<flutter::EncodableValue> > >&&) (__functor=..., __args=..., __args=...) at /home/swift/tizen-studio/tools/smart-build-interface/../i586-linux-gnueabi-gcc-9.2/lib/gcc/i586-tizen-linux-gnueabi/9.2.0/../../../../i586-tizen-linux-gnueabi/include/c++/9.2.0/bits/std_function.h:300
#4  0xb7380425 in std::function<void (flutter::MethodCall<flutter::EncodableValue> const&, std::unique_ptr<flutter::MethodResult<flutter::EncodableValue>, std::default_delete<flutter::MethodResult<flutter::EncodableValue> > >)>::operator()(flutter::MethodCall<flutter::EncodableValue> const&, std::unique_ptr<flutter::MethodResult<flutter::EncodableValue>, std::default_delete<flutter::MethodResult<flutter::EncodableValue> > >) const (this=0x8036f450, __args=..., __args=...) at /home/swift/tizen-studio/tools/smart-build-interface/../i586-linux-gnueabi-gcc-9.2/lib/gcc/i586-tizen-linux-gnueabi/9.2.0/../../../../i586-tizen-linux-gnueabi/include/c++/9.2.0/bits/std_function.h:690
#5  0xb737fffd in flutter::MethodChannel<flutter::EncodableValue>::SetMethodCallHandler(std::function<void (flutter::MethodCall<flutter::EncodableValue> const&, std::unique_ptr<flutter::MethodResult<flutter::EncodableValue>, std::default_delete<flutter::MethodResult<flutter::EncodableValue> > >)>) const::{lambda(unsigned char const*, unsigned int, std::function<void (unsigned char const*, unsigned int)>)#1}::operator()(unsigned char const*, unsigned int, std::function<void (unsigned char const*, unsigned int)>) const (this=0x8036f450, message=0xa0b65d30 "\a\022getPlatformVersion", message_size=21, reply=...) at /home/swift/Git/flutter-tizen/flutter/bin/cache/artifacts/engine/tizen-common/cpp_client_wrapper/include/flutter/method_channel.h:119
#6  0xb737fa49 in std::_Function_handler<void (unsigned char const*, unsigned int, std::function<void (unsigned char const*, unsigned int)>), flutter::MethodChannel<flutter::EncodableValue>::SetMethodCallHandler(std::function<void (flutter::MethodCall<flutter::EncodableValue> const&, std::unique_ptr<flutter::MethodResult<flutter::EncodableValue>, std::default_delete<flutter::MethodResult<flutter::EncodableValue> > >)>) const::{lambda(unsigned char const*, unsigned int, std::function<void (unsigned char const*, unsigned int)>)#1}>::_M_invoke(std::_Any_data const&, unsigned char const*&&, unsigned int&&, std::function<void (unsigned char const*, unsigned int)>&&) (__functor=..., __args=..., __args=..., __args=...) at /home/swift/tizen-studio/tools/smart-build-interface/../i586-linux-gnueabi-gcc-9.2/lib/gcc/i586-tizen-linux-gnueabi/9.2.0/../../../../i586-tizen-linux-gnueabi/include/c++/9.2.0/bits/std_function.h:300
#7  0xb733d109 in std::function<void (unsigned char const*, unsigned int, std::function<void (unsigned char const*, unsigned int)>)>::operator()(unsigned char const*, unsigned int, std::function<void (unsigned char const*, unsigned int)>) const (this=0x803398c8, __args=..., __args=..., __args=...) at /home/swift/tizen-studio/tools/smart-build-interface/../i586-linux-gnueabi-gcc-9.2/lib/gcc/i586-tizen-linux-gnueabi/9.2.0/../../../../i586-tizen-linux-gnueabi/include/c++/9.2.0/bits/std_function.h:690
#8  0xb733b107 in flutter::(anonymous namespace)::ForwardToHandler (messenger=0x8032cec0, message=0xbf8a6b40, user_data=0x803398c8) at cpp_client_wrapper/core_implementations.cc:58
#9  0xb74f0c6a in ?? () from target:/opt/usr/globalapps/com.example.native_plugin_example/bin/../lib/libflutter_tizen_mobile.so
#10 0xb74d73c8 in ?? () from target:/opt/usr/globalapps/com.example.native_plugin_example/bin/../lib/libflutter_tizen_mobile.so
#11 0xb53f800b in ?? () from target:/opt/usr/globalapps/com.example.native_plugin_example/bin/../lib/libflutter_engine.so
#12 0xb5406300 in ?? () from target:/opt/usr/globalapps/com.example.native_plugin_example/bin/../lib/libflutter_engine.so
#13 0xb5a3b502 in ?? () from target:/opt/usr/globalapps/com.example.native_plugin_example/bin/../lib/libflutter_engine.so
#14 0xb5403f7c in ?? () from target:/opt/usr/globalapps/com.example.native_plugin_example/bin/../lib/libflutter_engine.so
#15 0xb54055ff in ?? () from target:/opt/usr/globalapps/com.example.native_plugin_example/bin/../lib/libflutter_engine.so
#16 0xb53faf64 in ?? () from target:/opt/usr/globalapps/com.example.native_plugin_example/bin/../lib/libflutter_engine.so
#17 0xb53ed952 in FlutterEngineRunTask () from target:/opt/usr/globalapps/com.example.native_plugin_example/bin/../lib/libflutter_engine.so
#18 0xb74d7b0e in ?? () from target:/opt/usr/globalapps/com.example.native_plugin_example/bin/../lib/libflutter_tizen_mobile.so
#19 0xb74db989 in ?? () from target:/opt/usr/globalapps/com.example.native_plugin_example/bin/../lib/libflutter_tizen_mobile.so
#20 0xb74db15c in ?? () from target:/opt/usr/globalapps/com.example.native_plugin_example/bin/../lib/libflutter_tizen_mobile.so
#21 0xb74db9d1 in ?? () from target:/opt/usr/globalapps/com.example.native_plugin_example/bin/../lib/libflutter_tizen_mobile.so
#22 0xb53123e8 in ?? () from target:/lib/libecore.so.1
#23 0xb531308b in ?? () from target:/lib/libecore.so.1
#24 0xb52d790b in ?? () from target:/lib/libecore.so.1
#25 0xb52d7ffb in ?? () from target:/lib/libecore.so.1
#26 0xb52dd3d6 in ?? () from target:/lib/libecore.so.1
#27 0xb52dc2d4 in efl_loop_begin () from target:/lib/libecore.so.1
#28 0xb52d6388 in ecore_main_loop_begin () from target:/lib/libecore.so.1
#29 0xb3a33d9a in elm_run () from target:/lib/libelementary.so.1
#30 0xb4d620f7 in ?? () from target:/lib/libappcore-efl.so.1
#31 0xb4da33b2 in appcore_base_init () from target:/lib/libappcore-common.so.1
#32 0xb37c37d6 in appcore_ui_base_init () from target:/lib/libappcore-ui.so.1
#33 0xb4d62724 in appcore_efl_base_init () from target:/lib/libappcore-efl.so.1
#34 0xb74ab59d in ?? () from target:/lib/libcapi-appfw-application.so.0
#35 0xb74ab8a1 in ui_app_main () from target:/lib/libcapi-appfw-application.so.0
#36 0x8001fd2c in FlutterApp::Run (this=0xbf8a8728, argc=29, argv=0xbf8a8824) at flutter_app.cc:162
#37 0x8001dec4 in main (argc=29, argv=0xbf8a8824) at src/runner.cc:17

(after)

(gdb) bt
#0  0xb4da6ea5 in system_info_get_platform_string () from target:/lib/libcapi-system-info.so.0
#1  0xb73bd077 in (anonymous namespace)::NativePlugin::HandleMethodCall (this=0x80277380, method_call=..., result=...) at src/native_plugin_plugin.cc:48
#2  0xb73bcf1d in (anonymous namespace)::NativePlugin::RegisterWithRegistrar(flutter::PluginRegistrar*)::{lambda(auto:1 const&, auto:2)#1}::operator()<flutter::MethodCall<flutter::EncodableValue>, std::unique_ptr<flutter::MethodResult<flutter::MethodCall>, std::default_delete<flutter::MethodResult> > >(flutter::MethodCall<flutter::EncodableValue> const&, std::unique_ptr<flutter::MethodResult<flutter::MethodCall>, std::default_delete<flutter::MethodResult> >) const (this=0x802b0440, call=..., result=...) at src/native_plugin_plugin.cc:29
#3  0xb73bcce6 in std::_Function_handler<void (flutter::MethodCall<flutter::EncodableValue> const&, std::unique_ptr<flutter::MethodResult<flutter::EncodableValue>, std::default_delete<flutter::MethodResult<flutter::EncodableValue> > >), (anonymous namespace)::NativePlugin::RegisterWithRegistrar(flutter::PluginRegistrar*)::{lambda(auto:1 const&, auto:2)#1}>::_M_invoke(std::_Any_data const&, flutter::MethodCall<flutter::EncodableValue> const&, std::unique_ptr<flutter::MethodResult<flutter::EncodableValue>, std::default_delete<flutter::MethodResult<flutter::EncodableValue> > >&&) (__functor=..., __args=..., __args=...) at /home/swift/tizen-studio/tools/smart-build-interface/../i586-linux-gnueabi-gcc-9.2/lib/gcc/i586-tizen-linux-gnueabi/9.2.0/../../../../i586-tizen-linux-gnueabi/include/c++/9.2.0/bits/std_function.h:300
#4  0xb73bf425 in std::function<void (flutter::MethodCall<flutter::EncodableValue> const&, std::unique_ptr<flutter::MethodResult<flutter::EncodableValue>, std::default_delete<flutter::MethodResult<flutter::EncodableValue> > >)>::operator()(flutter::MethodCall<flutter::EncodableValue> const&, std::unique_ptr<flutter::MethodResult<flutter::EncodableValue>, std::default_delete<flutter::MethodResult<flutter::EncodableValue> > >) const (this=0x802b0440, __args=..., __args=...) at /home/swift/tizen-studio/tools/smart-build-interface/../i586-linux-gnueabi-gcc-9.2/lib/gcc/i586-tizen-linux-gnueabi/9.2.0/../../../../i586-tizen-linux-gnueabi/include/c++/9.2.0/bits/std_function.h:690
#5  0xb73beffd in flutter::MethodChannel<flutter::EncodableValue>::SetMethodCallHandler(std::function<void (flutter::MethodCall<flutter::EncodableValue> const&, std::unique_ptr<flutter::MethodResult<flutter::EncodableValue>, std::default_delete<flutter::MethodResult<flutter::EncodableValue> > >)>) const::{lambda(unsigned char const*, unsigned int, std::function<void (unsigned char const*, unsigned int)>)#1}::operator()(unsigned char const*, unsigned int, std::function<void (unsigned char const*, unsigned int)>) const (this=0x802b0440, message=0xabeaebc0 "\a\022getPlatformVersion", message_size=21, reply=...) at /home/swift/Git/flutter-tizen/flutter/bin/cache/artifacts/engine/tizen-common/cpp_client_wrapper/include/flutter/method_channel.h:119
#6  0xb73bea49 in std::_Function_handler<void (unsigned char const*, unsigned int, std::function<void (unsigned char const*, unsigned int)>), flutter::MethodChannel<flutter::EncodableValue>::SetMethodCallHandler(std::function<void (flutter::MethodCall<flutter::EncodableValue> const&, std::unique_ptr<flutter::MethodResult<flutter::EncodableValue>, std::default_delete<flutter::MethodResult<flutter::EncodableValue> > >)>) const::{lambda(unsigned char const*, unsigned int, std::function<void (unsigned char const*, unsigned int)>)#1}>::_M_invoke(std::_Any_data const&, unsigned char const*&&, unsigned int&&, std::function<void (unsigned char const*, unsigned int)>&&) (__functor=..., __args=..., __args=..., __args=...) at /home/swift/tizen-studio/tools/smart-build-interface/../i586-linux-gnueabi-gcc-9.2/lib/gcc/i586-tizen-linux-gnueabi/9.2.0/../../../../i586-tizen-linux-gnueabi/include/c++/9.2.0/bits/std_function.h:300
#7  0xb737c109 in std::function<void (unsigned char const*, unsigned int, std::function<void (unsigned char const*, unsigned int)>)>::operator()(unsigned char const*, unsigned int, std::function<void (unsigned char const*, unsigned int)>) const (this=0x8027a8b8, __args=..., __args=..., __args=...) at /home/swift/tizen-studio/tools/smart-build-interface/../i586-linux-gnueabi-gcc-9.2/lib/gcc/i586-tizen-linux-gnueabi/9.2.0/../../../../i586-tizen-linux-gnueabi/include/c++/9.2.0/bits/std_function.h:690
#8  0xb737a107 in flutter::(anonymous namespace)::ForwardToHandler (messenger=0x8026deb0, message=0xbfadad50, user_data=0x8027a8b8) at cpp_client_wrapper/core_implementations.cc:58
#9  0xb752fc6a in HandleMessage () at ../../flutter/shell/platform/common/incoming_message_dispatcher.cc:36
#10 0xb75163c8 in operator() () at ../../flutter/shell/platform/tizen/flutter_tizen_engine.cc:214
#11 __invoke () at ../../flutter/shell/platform/tizen/flutter_tizen_engine.cc:205
#12 0xb543700b in operator() () at ../../flutter/shell/platform/embedder/embedder.cc:1112
#13 __invoke<(lambda at ../../flutter/shell/platform/embedder/embedder.cc:1101:9) &, std::__1::unique_ptr<flutter::PlatformMessage, std::__1::default_delete<flutter::PlatformMessage> > > () at ../../third_party/libcxx/include/type_traits:3530
#14 __call<(lambda at ../../flutter/shell/platform/embedder/embedder.cc:1101:9) &, std::__1::unique_ptr<flutter::PlatformMessage, std::__1::default_delete<flutter::PlatformMessage> > > () at ../../third_party/libcxx/include/__functional_base:348
#15 operator() () at ../../third_party/libcxx/include/functional:1533
#16 operator() () at ../../third_party/libcxx/include/functional:1707
#17 0xb5445300 in operator() () at ../../third_party/libcxx/include/functional:1860
#18 operator() () at ../../third_party/libcxx/include/functional:2419
#19 HandlePlatformMessage () at ../../flutter/shell/platform/embedder/platform_view_embedder.cc:80
#20 0xb5a7a502 in operator() () at ../../flutter/shell/common/shell.cc:1203
#21 operator()<> () at ../../flutter/fml/make_copyable.h:24
#22 __invoke<fml::internal::CopyableLambda<(lambda at ../../flutter/shell/common/shell.cc:1200:27)> &> () at ../../third_party/libcxx/include/type_traits:3530
#23 __call<fml::internal::CopyableLambda<(lambda at ../../flutter/shell/common/shell.cc:1200:27)> &> () at ../../third_party/libcxx/include/__functional_base:348
#24 operator() () at ../../third_party/libcxx/include/functional:1533
#25 operator() () at ../../third_party/libcxx/include/functional:1707
#26 0xb5442f7c in operator() () at ../../third_party/libcxx/include/functional:1860
#27 operator() () at ../../third_party/libcxx/include/functional:2419
#28 PostTask () at ../../flutter/shell/platform/embedder/embedder_task_runner.cc:77
#29 0xb54445ff in PostTask () at ../../flutter/shell/platform/embedder/embedder_thread_host.cc:270
#30 0xb5439f64 in flutter::EmbedderEngine::RunTask(FlutterTask const*) () at ../../flutter/shell/platform/embedder/embedder_engine.cc:260
#31 0xb542c952 in FlutterEngineRunTask () at ../../flutter/shell/platform/embedder/embedder.cc:1963
#32 0xb7516b0e in operator()<FlutterTask> () at ../../flutter/shell/platform/tizen/flutter_tizen_engine.cc:68
#33 __invoke<(lambda at ../../flutter/shell/platform/tizen/flutter_tizen_engine.cc:67:37) &, const FlutterTask *> () at ../../third_party/libcxx/include/type_traits:3530
#34 __call<(lambda at ../../flutter/shell/platform/tizen/flutter_tizen_engine.cc:67:37) &, const FlutterTask *> () at ../../third_party/libcxx/include/__functional_base:348
#35 operator() () at ../../third_party/libcxx/include/functional:1533
#36 operator() () at ../../third_party/libcxx/include/functional:1707
#37 0xb751a989 in operator() () at ../../third_party/libcxx/include/functional:1860
#38 operator() () at ../../third_party/libcxx/include/functional:2419
#39 OnTaskExpired () at ../../flutter/shell/platform/tizen/tizen_event_loop.cc:107
#40 0xb751a15c in ExecuteTaskEvents () at ../../flutter/shell/platform/tizen/tizen_event_loop.cc:56
#41 0xb751a9d1 in operator() () at ../../flutter/shell/platform/tizen/tizen_event_loop.cc:25
#42 __invoke () at ../../flutter/shell/platform/tizen/tizen_event_loop.cc:23
#43 0xb53513e8 in ?? () from target:/lib/libecore.so.1
#44 0xb535208b in ?? () from target:/lib/libecore.so.1
#45 0xb531690b in ?? () from target:/lib/libecore.so.1
#46 0xb5316ffb in ?? () from target:/lib/libecore.so.1
#47 0xb531c3d6 in ?? () from target:/lib/libecore.so.1
#48 0xb531b2d4 in efl_loop_begin () from target:/lib/libecore.so.1
#49 0xb5315388 in ecore_main_loop_begin () from target:/lib/libecore.so.1
#50 0xb3a72d9a in elm_run () from target:/lib/libelementary.so.1
#51 0xb4da10f7 in ?? () from target:/lib/libappcore-efl.so.1
#52 0xb4de23b2 in appcore_base_init () from target:/lib/libappcore-common.so.1
#53 0xb38027d6 in appcore_ui_base_init () from target:/lib/libappcore-ui.so.1
#54 0xb4da1724 in appcore_efl_base_init () from target:/lib/libappcore-efl.so.1
#55 0xb74ea59d in ?? () from target:/lib/libcapi-appfw-application.so.0
#56 0xb74ea8a1 in ui_app_main () from target:/lib/libcapi-appfw-application.so.0
#57 0x80012d2c in FlutterApp::Run (this=0xbfadc938, argc=29, argv=0xbfadca34) at flutter_app.cc:162
#58 0x80010ec4 in main (argc=29, argv=0xbfadca34) at src/runner.cc:17

Text not appearing on samsung galaxy watch active 2

WhatsApp Image 2021-04-07 at 1 02 33 PM (1)

Sample Code
import 'package:flutter/material.dart';

void main() {
runApp(MyApp());
}

class MyApp extends StatelessWidget
{
@OverRide
Widget build(BuildContext context) {
// TODO: implement build
return MaterialApp(
home: Scaffold(
backgroundColor: Colors.red,
body: Center(child: Column(
children: [
Image.asset("assets/flutter_icon.png"),
Text("sojaasadaddd")
],
)),
),
);

}
}

localeResolutionCallback doesn't work correctly

Problem

  • If you use localeResolutioncallback, you get the wrong locale value
  • Sample codes
    // ...
    import 'package:flutter_localizations/flutter_localizations.dart';
    // ...
          localizationsDelegates: [
            GlobalMaterialLocalizations.delegate,
            GlobalWidgetsLocalizations.delegate,
            GlobalCupertinoLocalizations.delegate,
          ],
          localeResolutionCallback:
              (Locale locale, Iterable<Locale> supportedLocales) {
            print("localeResolutionCallback!!");
            print("locale.countryCode : " + locale.countryCode.toString());
            print("locale.languageCode : " + locale.languageCode.toString());
            return locale;
         }

How to reproduce

  1. Launch the app
  2. Change device language to another language
  3. Resume the app

as is

  • The locale value is always wrong.
    image

expected

  • The locale value should reflect the language of the device.
    image

Rotating the window and Positioning the software keyboard

Problem

  1. When the device is rotated, an animation of rotating the window should occur but it doesn't
  2. After the device is rotated, the keyboard should also be positioned correctly but it doesn't.

As-is

  • When the device is rotated, No rotating animation occurs.
  • screenshot
    Image Pasted at 2021-1-5 16-30

Expected(android)

  • When the device is rotated, you can see the animation of rotating the window
  • screenshot
    Screenshot_20210105-193420

Details

To solve these problems, I tried setting available rotation degrees on the window.

ecore_wl2_window_available_rotations_set

If you use the above API and you rotate the actual device, you can see that the window is also rotated according to the device orientation with an appropriate rotating animation. the keyboard is positioned also correctly.
But after that, the screen looks frozen.
*If you are using the scrollable sample app, you can easily see that the screen is frozen after rotating the device with the above API.

I tried the following to analyze and to solve the problem, but it didn't work.

  • Remove gl surface transformation
    • The screen may appear partially frozen. when pause-resume occurs, nothing will be shown(black screen).
  • After the device is rotated, re-create egl window surface after device rotated on the render thread
    • If you create a surface and clear the surface with any color, you can see that color momentarily. // It's natural.
    • However, once a rotation occurs, you can not see that color anymore. // this is very weird.
  • After the device is rotated, re-create wl2 window and egl window surface on the render thread
  • Create wl_egl_window* from Ecore_Wl2_Window and use it to create egl window surface

Please let me know if you know anything about this.

Improve the logging system

Previous discussion: #75 (comment)

  • The embedder should properly control its logging level based on the verbose_logging switch (which is enabled by flutter-tizen run --verbose-system-logs).
    • Example:
      fml::LogSettings log_settings;
      log_settings.min_log_level =
      settings.verbose_logging ? fml::LOG_INFO : fml::LOG_ERROR;
      fml::SetLogSettings(log_settings);
  • Remove unnecessary logs in the embedder or make them more informative. We should remove all occurrences of FT_LOGD and use only FT_LOGI/W/E.

How to load [abi:cxx11] symbol

I am researching for rendering flutter-tizen in NUI (Tizen Natural User Interface (C#))
For this, I must use DALi(Tizen C++ UIFW) in engine(tizen renderer).
Among the DALi APIs, there is an API that returns std::string and when I want to use this API, the link error occurred in engine build.
( ex: const std::string& Dali::Toolkit::ImageUrl::GetUrl() const)

tizen_renderer_ecore_wl2.cc:(.text._ZN7flutter21TizenRendererEcoreWl28SetupEGLEv+0x2d3): undefined reference to `Dali::Toolkit::ImageUrl::GetUrl() const

I found symbol for this API with the nm command. there is a [abi:cxx11] tag.

~/dev/os/engine/src ((HEAD detached at 4660f4a)) 16:08:11 $ nm -gDC tizen_tools/sysroot/x86/usr/lib/libdali2-toolkit.so | grep ImageUrl::GetUrl
0020fade T Dali::Toolkit::ImageUrl::GetUrl[abi:cxx11]() const

I was studying this and found that the engine compile script need __GLIBCXX_USE_CXX11_ABI = 1 //or 0 define.
(https://gcc.gnu.org/onlinedocs/libstdc++/manual/using_dual_abi.html)
I added it to build script and tried to build, but the problem was not resolved.

If you guys has any ideas for script modifications to use [abi:cxx11] api, please let me know.

(my tizen/Build.gn diff)

--- a/shell/platform/tizen/BUILD.gn
+++ b/shell/platform/tizen/BUILD.gn
@@ -21,6 +21,7 @@ source_set("flutter_engine") {
   lib_dirs = [ root_out_dir ]
 
   public_configs = [ ":embedder_rpath" ]
+  public_configs += [ "//build/config/compiler:rtti" ]
 
   deps = [ "//flutter/shell/platform/embedder:flutter_engine" ]
 }
@@ -52,6 +53,10 @@ config("rootstrap_include_dirs") {
     "$local_prefix/include/ecore-input-1",
     "$local_prefix/include/ecore-wayland-1",
     "$local_prefix/include/ecore-wl2-1",
+    "$local_prefix/include/dali",
+    "$local_prefix/include/dali-toolkit",
+    "$local_prefix/include/dali-adaptor",
+
     "$local_prefix/include/efl-1",
     "$local_prefix/include/efl-extension",
     "$local_prefix/include/eina-1",
@@ -144,6 +149,7 @@ template("embedder") {
 
     defines += invoker.defines
     defines += [ "FLUTTER_ENGINE_NO_PROTOTYPES" ]
+    defines += [ "_GLIBCXX_USE_CXX11_ABI=1"]
 
     configs +=
         [ "//flutter/shell/platform/common:desktop_library_implementation" ]
@@ -209,6 +215,9 @@ template("embedder") {
       ]
 
       libs += [
+        "dali2-core",
+        "dali2-adaptor",
+        "dali2-toolkit",
         "ecore_wl2",
         "tizen-extension-client",
       ]

compiler/build.gn

diff --git a/build/config/compiler/BUILD.gn b/build/config/compiler/BUILD.gn
index 9b5899e..3e5cc8e 100644
--- a/build/config/compiler/BUILD.gn
+++ b/build/config/compiler/BUILD.gn
@@ -631,17 +631,13 @@ if (is_win) {
 
   if (!use_xcode) {
     default_warning_flags += [
-      "-Wno-unused-but-set-parameter",
-      "-Wno-unused-but-set-variable",
       "-Wno-implicit-int-float-conversion",
       "-Wno-c99-designator",
       "-Wno-deprecated-copy",
       # Needed for compiling Skia with clang-12
-      "-Wno-psabi",
     ]
     if (!is_fuchsia) {
       default_warning_flags += [
-        "-Wno-non-c-typedef-for-linkage",
         "-Wno-range-loop-construct",
       ]
     }
@@ -678,6 +674,7 @@ config("chromium_code") {
     defines = [
       "__STDC_CONSTANT_MACROS",
       "__STDC_FORMAT_MACROS",
+      "_GLIBCXX_USE_CXX11_ABI=1"
     ]
 
     if (!using_sanitizer && (!is_linux || !is_clang)) {
@@ -718,6 +715,10 @@ config("no_chromium_code") {
 config("rtti") {
   if (is_win) {
     cflags_cc = [ "/GR" ]
+  } else {
+    rtti_flags = [ "-frtti" ]
+    cflags_cc = rtti_flags
+    cflags_objcc = rtti_flags
   }
 }
 config("no_rtti") {

tizen-tools

diff --git a/sysroot/build-rootfs.py b/sysroot/build-rootfs.py
index 06d6768..b11b2b1 100755
--- a/sysroot/build-rootfs.py
+++ b/sysroot/build-rootfs.py
@@ -62,6 +62,12 @@ unifiedPackages = [
     'edje-devel',
     'eet',
     'eet-devel',
+    'dali2',
+    'dali2-devel',
+    'dali2-adaptor',
+    'dali2-adaptor-devel',
+    'dali2-toolkit',
+    'dali2-toolkit-devel',
     'efl-devel',
     'efl-extension',
     'efl-extension-devel',
@@ -132,11 +138,11 @@ parser.add_argument(
 parser.add_argument(
     '-b', '--base-repo', metavar='URL', type=str,
     help='url to the base packages repository',
-    default='http://download.tizen.org/snapshots/tizen/5.5-base/latest/repos/standard/packages')
+    default='http://download.tizen.org/snapshots/tizen/6.5-base/latest/repos/standard/packages')
 parser.add_argument(
     '-u', '--unified-repo', metavar='URL', type=str,
     help='url to the unified packages repository',
-    default='http://download.tizen.org/snapshots/tizen/5.5-unified/latest/repos/standard/packages')
+    default='http://download.tizen.org/snapshots/tizen/6.5-unified/latest/repos/standard/packages')
 args = parser.parse_args()
 
 if not args.output:

Sample Dali code

   #include "dali-toolkit/public-api/image-loader/image-url.h"
   #include "dali-toolkit/dali-toolkit.h"
   #include "dali/devel-api/adaptor-framework/native-image-source-queue.h"
   #include "tbm_surface.h"
   #include "tbm_surface_queue.h"
    ...
    tbm_surface_queue_h mTbmQueue = nullptr;
    Dali::NativeImageSourceQueuePtr mNativeImageQueue = nullptr;
    Dali::Texture mNativeTexture;
    ...
    mTbmQueue = tbm_surface_queue_create(3 , 500, 500, TBM_FORMAT_ARGB8888, 0);
    mNativeImageQueue = Dali::NativeImageSourceQueue::New(mTbmQueue);
    mNativeTexture = Dali::Texture::New(*mNativeImageQueue);
    Dali::Toolkit::ImageUrl imageUrl = Dali::Toolkit::ImageUrl::New(mNativeTexture);
    std::string url = imageUrl.GetUrl();  //<< Error

    FT_LOG(Error) << "CJS URL : " << url;

Implement rotation on TizenRendererEvasGL

We should fully implement screen rotation on evas gl

image

to reproduce this you must use kEvasGL

class App : public FlutterApp {
 public:
  bool OnCreate() {
    renderer_type_ = FlutterRendererType::kEvasGL;
    if (FlutterApp::OnCreate()) {
      RegisterPlugins(this);
    }
    return IsRunning();
  }
};

Engine build fails

I am trying to build engine from flutter-tizen/engine repo, to use it with flutter. I am following the manual from https://github.com/flutter-tizen/engine/wiki/Building-the-engine and I have been stuck on point 5. from this part of the manual https://github.com/flutter/flutter/wiki/Setting-up-the-Engine-development-environment:

  1. gclient sync in that [flutter/engine] directory. This will fetch all the source code that Flutter depends on. Avoid interrupting this script, as doing so can leave your repository in an inconsistent state that is tedious to clean up. (This step automatically runs git clone, among other things.)

When I use "https://github.com/flutter-tizen/engine.git" as the "url" in .gclient file, the gclient sync command fails with the following output:

(flutter) [~/prog/github/flutter/engine]$ gclient sync                                                                                            *[master]

________ running 'git -c core.deltaBaseCacheLimit=2g clone --no-checkout --progress https://github.com/flutter-tizen/engine.git /home/p.wasowski2/prog/github
/flutter/engine/src/_gclient_flutter_rgad74su' in '/home/p.wasowski2/prog/github/flutter/engine'
Cloning into '/home/p.wasowski2/prog/github/flutter/engine/src/_gclient_flutter_rgad74su'...
remote: Enumerating objects: 220707, done.
remote: Total 220707 (delta 0), reused 0 (delta 0), pack-reused 220707
Receiving objects: 100% (220707/220707), 208.27 MiB | 28.70 MiB/s, done.
Resolving deltas: 100% (161411/161411), done.
Checking connectivity... done.
Syncing projects: 100% (106/106), done.

Running hooks:  77% ( 7/ 9) linux_sysroot_x64
________ running 'vpython src/build/linux/sysroot_scripts/install-sysroot.py --arch=x64' in '/home/p.wasowski2/prog/github/flutter/engine'
Installing Debian sid amd64 root image: /home/p.wasowski2/prog/github/flutter/engine/src/build/linux/debian_sid_amd64-sysroot
Downloading https://commondatastorage.googleapis.com/chrome-linux-sysroot/toolchain/79a7783607a69b6f439add567eb6fcb48877085c/debian_sid_amd64_sysroot.tar.xz
Running hooks:  88% ( 8/ 9) linux_sysroot_arm64
________ running 'vpython src/build/linux/sysroot_scripts/install-sysroot.py --arch=arm64' in '/home/p.wasowski2/prog/github/flutter/engine'
Installing Debian sid arm64 root image: /home/p.wasowski2/prog/github/flutter/engine/src/build/linux/debian_sid_arm64-sysroot
Downloading https://commondatastorage.googleapis.com/chrome-linux-sysroot/toolchain/2cade9ee1ca9186b28ac768c19e1ab7c45ee0600/debian_sid_arm64_sysroot.tar.xz
Running hooks: 100% ( 9/ 9) dart package config
________ running 'vpython src/flutter/tools/run_third_party_dart.py' in '/home/p.wasowski2/prog/github/flutter/engine'
Resolving dependencies...
+ charcode 1.2.0
+ collection 1.15.0
+ package_config 2.0.0
+ path 1.8.0
+ pub_semver 2.0.0
+ source_span 1.8.1
+ string_scanner 1.1.0
+ term_glyph 1.2.0
+ yaml 3.1.0
Changed 9 dependencies!
Package generate_package_config is currently active at path "/home/p.wasowski2/prog/github/flutter/engine/src/flutter/tools/generate_package_config".
Activated generate_package_config 0.0.0 at path "/home/p.wasowski2/prog/github/flutter/engine/src/flutter/tools/generate_package_config".
Unable to spawn isolate: src/flutter/tools/generate_package_config/bin/generate_from_legacy.dart:10:8: Error: Error when reading '../../../../.pub-cache/host
ed/pub.dartlang.org/package_config-2.0.0/lib/packages_file.dart': No such file or directory
import 'package:package_config/packages_file.dart'; // ignore: deprecated_member_use
       ^
src/flutter/tools/generate_package_config/bin/generate_from_legacy.dart:28:20: Error: Method not found: 'parse'.
  var packageMap = parse(await packagesFile.readAsBytes(), packagesFile.uri);
                   ^^^^^
Traceback (most recent call last):
  File "src/flutter/tools/run_third_party_dart.py", line 14, in <module>
    subprocess.check_call([os.path.join(leading, pub), "global", "run", "generate_package_config:generate_from_legacy", "src/flutter/flutter_frontend_server/
.packages"])
  File "/home/p.wasowski2/prog/github/depot_tools/bootstrap-3.8.0.chromium.8_bin/python/lib/python2.7/subprocess.py", line 190, in check_call
    raise CalledProcessError(retcode, cmd)
subprocess.CalledProcessError: Command '['src/third_party/dart/tools/sdks/dart-sdk/bin/pub', 'global', 'run', 'generate_package_config:generate_from_legacy',
 'src/flutter/flutter_frontend_server/.packages']' returned non-zero exit status 1
Error: Command 'vpython src/flutter/tools/run_third_party_dart.py' returned non-zero exit status 1 in /home/p.wasowski2/prog/github/flutter/engine

The contents of .gclient file in flutter/engine:

solutions = [
  {
    "managed": False,
    "name": "src/flutter",
    "url": "https://github.com/flutter-tizen/engine.git",
    "custom_deps": {},
    "deps_file": "DEPS",
    "safesync_url": "",
  },
]

As a workaround I have changed the version of package_config in flutter/engine/src/flutter/tools/generate_package_config/pubspec.yaml from any to 1.9.3 - after that change gclient sync succeeds. Nevertheless, this is only a workaround.

Could you please help me fixing the problem?

Better D-pad navigation support for TV

On TV, a focus cannot move to specific widgets in an app through arrow buttons (D-pad) on remote controls if the app has one or more text field widgets.

For example, in the "share_plus" plugin demo, the "Share subject" text field and the "Share" button can never get a focus because the text field on the top ("Share text") swallows all arrow button clicks. (I cannot upload a screenshot due to the company firewall.)

This is a TV-specific issue because the only input device for TV is a remote control by default. Other profiles and platforms (such as Android) do not have this problem because they all support touch/pointer-based navigation.

Related links:

cc @bbrto21

"xkbcommon: ERROR: couldn't find a Compose file for locale" on app launch

This issue has been reported in #53:

Non-fatal error "xkbcommon: ERROR: couldn't find a Compose file for locale" on app launch (unrelated to Flutter)

Reproduction by @bbrto21:

Launch Settings
Go - Language and input
Go - Display language
Choose a language other than English
Launch flutter-app

dlog output:

E/ConsoleMessage(24758): xkbcommon: ERROR: couldn't find a Compose file for locale "pl_PL.UTF-8"

Disable logging threads when running in release mode

Dart messages should be logged through the new logging callback recently added to the embedder APIs as suggested by #105.

The current plan:

  • When running in release mode, only Dart messages are logged to dlog.
  • When running in debug mode, Dart messages and all stdout/stderr messages are logged to dlog.

Removing unmanaged APIs

Problem

Unmanaged APIs should not be used for app store registration.
(This issue is also related to flutter-tizen/flutter-tizen#10. because wayland related functions are also unmanaged APIs)

refer to :

gear_core_allowlist.txt (List of APIs rejected by store)

  • eglBindAPI[libflutter.so]
  • eglCreateContext[libflutter.so]
  • eglDestroyContext[libflutter.so]
  • eglCreateWindowSurface[libflutter.so]
  • eglDestroySurface[libflutter.so]
  • eglTerminate[libflutter.so]
  • eglMakeCurrent[libflutter.so]
  • eglSwapBuffers[libflutter.so]
  • eglCreatePbufferSurface[libflutter.so]
  • eglGetCurrentDisplay[libflutter.so]
  • eglQueryString[libflutter.so]
  • eglChooseConfig[libflutter.so]
  • eglGetError[libflutter.so]
  • eglInitialize[libflutter.so]
  • eglGetProcAddress[libflutter.so]
  • eglGetDisplay[libflutter.so]
  • ecore_wl2_window_geometry_get[libflutter.so]
  • ecore_wl2_window_show[libflutter.so]
  • ecore_wl2_egl_window_resize_with_rotation[libflutter.so]
  • ecore_wl2_sync[libflutter.so]
  • ecore_wl2_window_free[libflutter.so]
  • ecore_wl2_display_connect[libflutter.so]
  • ecore_wl2_egl_window_native_get[libflutter.so]
  • ecore_wl2_egl_window_create[libflutter.so]
  • ecore_wl2_window_new[libflutter.so]
  • ecore_wl2_window_type_set[libflutter.so]
  • ecore_wl2_display_disconnect[libflutter.so]
  • ecore_wl2_egl_window_destroy[libflutter.so]
  • ecore_wl2_init[libflutter.so]
  • ecore_wl2_display_get[libflutter.so]
  • ecore_wl2_window_alpha_set[libflutter.so]
  • ecore_wl2_window_id_get[libflutter.so]
  • ecore_wl2_shutdown[libflutter.so]
  • ecore_wl2_window_aux_hint_add[libflutter.so]
  • ecore_device_name_get[libflutter.so]
  • ecore_device_class_get[libflutter.so]
  • ecore_device_subclass_get[libflutter.so]
  • tdm_client_vblank_destroy[libflutter.so]
  • tdm_client_handle_events[libflutter.so]
  • tdm_client_get_output[libflutter.so]
  • tdm_client_create[libflutter.so]
  • tdm_client_destroy[libflutter.so]
  • tdm_client_vblank_set_enable_fake[libflutter.so]
  • tdm_client_output_create_vblank[libflutter.so]
  • tdm_client_vblank_wait[libflutter.so]
  • tbm_surface_internal_is_valid[libflutter.so]
  • tbm_surface_internal_unref[libflutter.so]
  • tbm_surface_internal_ref[libflutter.so]
  • _ZTHN4dart8OSThread18current_vm_thread_E[libflutter.so]
  • __dlog_print[libflutter.so]

Result of coverity scan at engine

I know coverty scan is a good tool, and if you're lucky you can find a place to fix it. (Unfortunately not in most cases. ๐Ÿ˜„ )

For fun, I ran it based on the current latest and got the following results.
image

Here is tizen only
whole result

I'm going to try and see if there's anything I can do. Those who are interested may want to take a look.

[VD] TV๋‚ด์˜ App Focus ์•ˆ๋ณด์ž„ ์ด์Šˆ

์•ˆ๋…•ํ•˜์„ธ์š”.

TV์— Sample App์„ ์˜ฌ๋ ค๋†“๊ณ  ํ…Œ์ŠคํŠธ๋ฅผ ํ•˜๋‹ค๋ณด๋ฉด,
์ผ๋ถ€ ๋ฐฐ๊ฒฝ์ด ํฐ์ƒ‰์„ ๊ฐ€์ง„ element์—์„œ๋Š” Focus๊ฐ€ ์ž˜ ๋ˆˆ์— ๋„์ง€ ์•Š์•„
๊ฐœ์„ ์ด ๊ฐ€๋Šฅํ• ์ง€ ๋ฌธ์˜ํ•˜๊ณ ์ž ์ด์Šˆ๋ฅผ ๋‚จ๊น๋‹ˆ๋‹ค.

ํ˜น์€ ์•ฑ ๊ฐœ๋ฐœ์ž๊ฐ€ Focus๋ฅผ ๋ฐ›์€ widget์— ๋Œ€ํ•ด ํ…Œ๋‘๋ฆฌ๋ฅผ ์ถ”๊ฐ€ํ•˜๋„๋ก
๊ตฌํ˜„ ๊ฐ€์ด๋“œ๋ฅผ ํ•ด์•ผํ•  ๋ถ€๋ถ„์ธ์ง€ ๋‹ต๋ณ€ ์ฃผ์‹œ๋ฉด ๊ฐ์‚ฌํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

http://wiki.vd.sec.samsung.net/pages/viewpage.action?pageId=174034907
์ž์„ธํ•œ ๊ทธ๋ฆผ์€ ์œ„์˜ URL์„ ์ฐธ๊ณ ํ•ด ์ฃผ์„ธ์š”.

Flutter 2.0.1 migration issues

  • Clang 12 build flag (-Wno-psabi) issue
    • Fuschia/Linux build now uses clang 12 by default but the Tizen toolchain is still based on clang 10.
    • Building the Tizen engine with the Fuschia toolchain has failed because required libraries are not available for armv7-linux-gnueabi target (see buildtools/linux-x64/clang/lib).
    • Thus, similarly to the -Wno-non-c-typedef-for-linkage flag, we have to remove the new flag from build/config/compiler/BUILD.gn manually.
  • TextInputModel API changes (flutter#21612, flutter#21854)
    • Done!
  • SDK artifacts cross-compilation issue
    • The same build error as flutter/flutter#74322 which was caused by flutter#20254.
    • We don't need to cross-build SDK artifacts for Tizen armv7l and x86. So we need to patch the build rule temporarily. (I'm not going to PR it in the upstream right now.)
  • flutter_texture_registrar.h API conflicts
    • The following APIs have been added (flutter#19405):
      • FlutterDesktopRegistrarGetTextureRegistrar
      • FlutterDesktopTextureRegistrarRegisterExternalTexture
      • FlutterDesktopTextureRegistrarUnregisterExternalTexture
      • FlutterDesktopTextureRegistrarMarkExternalTextureFrameAvailable
    • but we already have:
      • FlutterPluginRegistrarGetTexture
      • FlutterRegisterExternalTexture
      • FlutterUnregisterExternalTexture
      • FlutterMarkExternalTextureFrameAvailable
    • I tried to remove our header and use theirs by renaming the functions in flutter_tizen.cc file, but the parameter tbm_surface was not available for FlutterDesktopTextureRegistrarMarkExternalTextureFrameAvailable. How should we deal with this? @xiaowei-guan @bbrto21
    • My attempt: swift-kim@1d72ddb (see the commented out section in flutter_tizen.cc)
  • Embedder API changes?
    • I haven't checked yet. Done

TextInputType.numberWithOptions doesn't work with decimal and signed option

Tested on emulator mobile-6.0-x86
TextInputType.numberWithOptions with decimal and signed option doesn't work.

Numpad, backward and enter buttons are enabled,
but other buttons are disabled.

Decimal and minus signs are not added to the field.

TextField(
              controller: controller,
              keyboardType:
                  const TextInputType.numberWithOptions(signed: true, decimal: true),
              decoration: const InputDecoration(
                  enabledBorder: UnderlineInputBorder(
                    borderSide: BorderSide(color: Colors.blue, width: 2),
                  ),
                  hintText: 'decimal input'),
            ),

์Šคํฌ๋ฆฐ์ƒท, 2021-10-06 09-10-18

flutter-tizen doctor -v
[โœ“] Flutter (Channel unknown, 2.2.1, on Linux, locale ko_KR.UTF-8)
    โ€ข Flutter version 2.2.1 at /home/yeonwoo/flutter_tizen/flutter-tizen/flutter
    โ€ข Framework revision 02c026b03c (4๋‹ฌ ์ „), 2021-05-27 12:24:44 -0700
    โ€ข Engine revision 0fdb562ac8
    โ€ข Dart version 2.13.1

[โœ“] Tizen toolchain - develop for Tizen devices
    โ€ข Framework revision 80b502bdae (8์ผ ์ „), 2021-09-28 10:13:38 +0900
    โ€ข Engine revision 8385e13d11
    โ€ข Tizen Studio 4.1.1 at /home/yeonwoo/tizen-studio
    โ€ข .NET SDK 5.0.400 at /usr/bin/dotnet

[โœ“] Connected device (1 available)
    โ€ข Tizen m-0727-2 (mobile)        โ€ข emulator-26101  โ€ข flutter-tester โ€ข Tizen 6.0 (emulator)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.