Skip to content

Commit 925d5a9

Browse files
authored
[keyboard_detection_tizen] Introduce keyboard_detection_tizen (#1020)
1 parent cd81ba0 commit 925d5a9

20 files changed

Lines changed: 628 additions & 0 deletions

.github/recipe.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ plugins:
66
flutter_inappwebview: ["tv-9.0"]
77
flutter_tts: ["tv-9.0"]
88
integration_test: ["tv-9.0"]
9+
keyboard_detection_tizen: ["tv-9.0"]
910
messageport: ["tv-9.0"]
1011
package_info_plus: ["tv-9.0"]
1112
path_provider: ["tv-9.0"]

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ The _"non-endorsed"_ status means that the plugin is not endorsed by the origina
2727
| [**google_sign_in_tizen**](packages/google_sign_in) | [google_sign_in](https://pub.dev/packages/google_sign_in) (1st-party) | [![pub package](https://img.shields.io/pub/v/google_sign_in_tizen.svg)](https://pub.dev/packages/google_sign_in_tizen) | No |
2828
| [**in_app_purchase_tizen**](packages/in_app_purchase) | [in_app_purchase](https://pub.dev/packages/in_app_purchase) (1st-party) | [![pub package](https://img.shields.io/pub/v/in_app_purchase_tizen.svg)](https://pub.dev/packages/in_app_purchase_tizen) | No |
2929
| [**integration_test_tizen**](packages/integration_test) | [integration_test](https://github.com/flutter/flutter/tree/main/packages/integration_test) (1st-party) | [![pub package](https://img.shields.io/pub/v/integration_test_tizen.svg)](https://pub.dev/packages/integration_test_tizen) | No |
30+
| [**keyboard_detection_tizen**](packages/keyboard_detection_tizen) | (Tizen-only) | [![pub package](https://img.shields.io/pub/v/keyboard_detection_tizen.svg)](https://pub.dev/packages/keyboard_detection_tizen) | N/A |
3031
| [**messageport_tizen**](packages/messageport) | (Tizen-only) | [![pub package](https://img.shields.io/pub/v/messageport_tizen.svg)](https://pub.dev/packages/messageport_tizen) | N/A |
3132
| [**network_info_plus_tizen**](packages/network_info_plus) | [network_info_plus](https://pub.dev/packages/network_info_plus) (1st-party) | [![pub package](https://img.shields.io/pub/v/network_info_plus_tizen.svg)](https://pub.dev/packages/network_info_plus_tizen) | No |
3233
| [**package_info_plus_tizen**](packages/package_info_plus) | [package_info_plus](https://pub.dev/packages/package_info_plus) (1st-party) | [![pub package](https://img.shields.io/pub/v/package_info_plus_tizen.svg)](https://pub.dev/packages/package_info_plus_tizen) | No |
@@ -68,6 +69,7 @@ The _"non-endorsed"_ status means that the plugin is not endorsed by the origina
6869
| [**google_sign_in_tizen**](packages/google_sign_in) | ✔️ | ✔️ | ✔️ |
6970
| [**in_app_purchase_tizen**](packages/in_app_purchase) | ✔️ ||| Only applicable for TV |
7071
| [**integration_test_tizen**](packages/integration_test) | ✔️ | ✔️ | ✔️ |
72+
| [**keyboard_detection_tizen**](packages/keyboard_detection_tizen) | ✔️ | ✔️ | ✔️ |
7173
| [**messageport_tizen**](packages/messageport) | ✔️ | ✔️ | ✔️ |
7274
| [**network_info_plus_tizen**](packages/network_info_plus) | ✔️ || ✔️ | API not supported on emulator. Need plugin-prebuilt to run wifi on RPI. |
7375
| [**package_info_plus_tizen**](packages/package_info_plus) | ✔️ | ✔️ | ✔️ |
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
# Miscellaneous
2+
*.class
3+
*.log
4+
*.pyc
5+
*.swp
6+
.DS_Store
7+
.atom/
8+
.buildlog/
9+
.history
10+
.svn/
11+
12+
# IntelliJ related
13+
*.iml
14+
*.ipr
15+
*.iws
16+
.idea/
17+
18+
# Flutter/Dart/Pub related
19+
**/doc/api/
20+
.dart_tool/
21+
.flutter-plugins
22+
.flutter-plugins-dependencies
23+
.packages
24+
.pub-cache/
25+
.pub/
26+
build/
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
## 0.1.0
2+
3+
* Initial release.
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
Copyright (c) 2026 Samsung Electronics Co., Ltd. All rights reserved.
2+
3+
Redistribution and use in source and binary forms, with or without modification,
4+
are permitted provided that the following conditions are met:
5+
6+
* Redistributions of source code must retain the above copyright
7+
notice, this list of conditions and the following disclaimer.
8+
* Redistributions in binary form must reproduce the above
9+
copyright notice, this list of conditions and the following
10+
disclaimer in the documentation and/or other materials provided
11+
with the distribution.
12+
* Neither the name of the copyright holder nor the names of the
13+
contributors may be used to endorse or promote products derived
14+
from this software without specific prior written permission.
15+
16+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
17+
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18+
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
20+
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21+
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22+
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
23+
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24+
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25+
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
# keyboard_detection_tizen
2+
3+
A Tizen-specific Flutter plugin that detects software keyboard (input panel)
4+
visibility and size on Tizen devices. The public API mirrors the
5+
[`keyboard_detection`](https://pub.dev/packages/keyboard_detection) package.
6+
7+
The original `keyboard_detection` package detects keyboard visibility from
8+
`MediaQuery.viewInsets.bottom`, which is not populated on Tizen. This plugin
9+
listens to the `tizen/internal/inputpanel` event channel exposed by the
10+
flutter-tizen embedder instead, and reads the keyboard geometry (height,
11+
width, position) from the same channel.
12+
13+
> **Warning**
14+
> Requires flutter-tizen `3.41.9-tizen.1.0.0` or later. Earlier versions
15+
> of the embedder do not publish geometry on the
16+
> `tizen/internal/inputpanel` channel, so the controller will stay in
17+
> `KeyboardState.unknown`.
18+
19+
## Usage
20+
21+
```yaml
22+
dependencies:
23+
keyboard_detection_tizen: ^0.1.0
24+
```
25+
26+
```dart
27+
import 'package:keyboard_detection_tizen/keyboard_detection_tizen.dart';
28+
29+
final controller = KeyboardDetectionController(
30+
onChanged: (state) => debugPrint('keyboard: $state'),
31+
);
32+
33+
@override
34+
Widget build(BuildContext context) {
35+
return Scaffold(
36+
body: Column(
37+
children: [
38+
const TextField(),
39+
StreamBuilder<KeyboardState>(
40+
stream: controller.stream,
41+
builder: (_, snapshot) => Text(
42+
'state: ${snapshot.data ?? KeyboardState.unknown} '
43+
'size: ${controller.size}',
44+
),
45+
),
46+
],
47+
),
48+
);
49+
}
50+
```
51+
52+
## Limitations
53+
54+
- The Tizen input panel channel emits `show` / `hide` / `will_show` only.
55+
`KeyboardState.hiding` is therefore never reached on Tizen.
56+
- Geometry values are physical pixels reported by `ecore_imf`. Convert with
57+
`MediaQueryData.devicePixelRatio` if you need logical pixels.
58+
- Floating / split keyboards are not supported.
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
# Miscellaneous
2+
*.class
3+
*.log
4+
*.pyc
5+
*.swp
6+
.DS_Store
7+
.atom/
8+
.buildlog/
9+
.history
10+
.svn/
11+
12+
# IntelliJ related
13+
*.iml
14+
*.ipr
15+
*.iws
16+
.idea/
17+
18+
# Flutter/Dart/Pub related
19+
**/doc/api/
20+
.dart_tool/
21+
.flutter-plugins
22+
.flutter-plugins-dependencies
23+
.packages
24+
.pub-cache/
25+
.pub/
26+
/build/
27+
28+
# Symbolication related
29+
app.*.symbols
30+
31+
# Obfuscation related
32+
app.*.map.json
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
# keyboard_detection_tizen_example
2+
3+
Demonstrates how to use the `keyboard_detection_tizen` plugin.
4+
5+
## Getting Started
6+
7+
To run this app on your Tizen device, use [flutter-tizen](https://github.com/flutter-tizen/flutter-tizen).
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
// Copyright 2026 Samsung Electronics Co., Ltd. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
import 'package:flutter/services.dart';
6+
import 'package:flutter_test/flutter_test.dart';
7+
import 'package:integration_test/integration_test.dart';
8+
import 'package:keyboard_detection_tizen/keyboard_detection_tizen.dart';
9+
10+
void main() {
11+
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
12+
13+
const String channelName = 'tizen/internal/inputpanel';
14+
const StandardMethodCodec codec = StandardMethodCodec();
15+
16+
Future<void> emit(WidgetTester tester, Map<String, Object?> payload) async {
17+
final ByteData data = codec.encodeSuccessEnvelope(payload);
18+
await tester.binding.defaultBinaryMessenger.handlePlatformMessage(
19+
channelName,
20+
data,
21+
(_) {},
22+
);
23+
}
24+
25+
testWidgets('reports visible on show event', (WidgetTester tester) async {
26+
final KeyboardDetectionController controller =
27+
KeyboardDetectionController();
28+
await emit(tester, <String, Object?>{'state': 'show'});
29+
await tester.pump();
30+
expect(controller.state, KeyboardState.visible);
31+
expect(controller.stateAsBool(), isTrue);
32+
await controller.dispose();
33+
});
34+
35+
testWidgets('reports hidden on hide event', (WidgetTester tester) async {
36+
final KeyboardDetectionController controller =
37+
KeyboardDetectionController();
38+
await emit(tester, <String, Object?>{'state': 'show'});
39+
await tester.pump();
40+
await emit(tester, <String, Object?>{'state': 'hide'});
41+
await tester.pump();
42+
expect(controller.state, KeyboardState.hidden);
43+
expect(controller.stateAsBool(), isFalse);
44+
await controller.dispose();
45+
});
46+
}
Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
// Copyright 2026 Samsung Electronics Co., Ltd. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
// ignore_for_file: public_member_api_docs
6+
7+
import 'package:flutter/material.dart';
8+
import 'package:keyboard_detection_tizen/keyboard_detection_tizen.dart';
9+
10+
void main() {
11+
runApp(const MyApp());
12+
}
13+
14+
class MyApp extends StatelessWidget {
15+
const MyApp({super.key});
16+
17+
@override
18+
Widget build(BuildContext context) {
19+
return MaterialApp(
20+
title: 'keyboard_detection_tizen example',
21+
theme: ThemeData(primarySwatch: Colors.blue),
22+
home: const HomePage(),
23+
);
24+
}
25+
}
26+
27+
class HomePage extends StatefulWidget {
28+
const HomePage({super.key});
29+
30+
@override
31+
State<HomePage> createState() => _HomePageState();
32+
}
33+
34+
class _HomePageState extends State<HomePage> {
35+
late final KeyboardDetectionController _controller;
36+
37+
@override
38+
void initState() {
39+
super.initState();
40+
_controller = KeyboardDetectionController(
41+
onChanged: (KeyboardState state) {
42+
debugPrint('keyboard_detection_tizen: $state');
43+
},
44+
);
45+
}
46+
47+
@override
48+
void dispose() {
49+
_controller.dispose();
50+
super.dispose();
51+
}
52+
53+
@override
54+
Widget build(BuildContext context) {
55+
return Scaffold(
56+
appBar: AppBar(title: const Text('Keyboard Detection')),
57+
body: SafeArea(
58+
child: Padding(
59+
padding: const EdgeInsets.all(24),
60+
child: Column(
61+
mainAxisAlignment: MainAxisAlignment.center,
62+
children: <Widget>[
63+
StreamBuilder<KeyboardState>(
64+
stream: _controller.stream,
65+
initialData: _controller.state,
66+
builder: (BuildContext _, AsyncSnapshot<KeyboardState> snap) {
67+
final KeyboardState s = snap.data ?? KeyboardState.unknown;
68+
return Column(
69+
key: const Key('status'),
70+
children: <Widget>[
71+
Text(
72+
'state: ${s.name}',
73+
key: const Key('state-text'),
74+
style: Theme.of(context).textTheme.titleMedium,
75+
),
76+
const SizedBox(height: 8),
77+
Text(
78+
'visible: ${_controller.stateAsBool() ?? "unknown"}',
79+
key: const Key('visible-text'),
80+
),
81+
const SizedBox(height: 8),
82+
Text(
83+
'width: ${_controller.width.toStringAsFixed(1)} '
84+
'/ size(height): ${_controller.size.toStringAsFixed(1)} ',
85+
key: const Key('size-text'),
86+
),
87+
const SizedBox(height: 8),
88+
Text(
89+
'position: '
90+
'(${_controller.position.dx.toStringAsFixed(1)}, '
91+
'${_controller.position.dy.toStringAsFixed(1)})',
92+
key: const Key('position-text'),
93+
),
94+
],
95+
);
96+
},
97+
),
98+
const SizedBox(height: 32),
99+
const TextField(
100+
decoration: InputDecoration(
101+
labelText: 'Tap here to open keyboard',
102+
),
103+
),
104+
],
105+
),
106+
),
107+
),
108+
);
109+
}
110+
}

0 commit comments

Comments
 (0)