Flutter Engine
The Flutter Engine
PlatformChannel.java
Go to the documentation of this file.
1// Copyright 2013 The Flutter Authors. 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
5package io.flutter.embedding.engine.systemchannels;
6
7import android.content.pm.ActivityInfo;
8import androidx.annotation.NonNull;
9import androidx.annotation.Nullable;
10import androidx.annotation.VisibleForTesting;
11import io.flutter.Log;
12import io.flutter.embedding.engine.dart.DartExecutor;
13import io.flutter.plugin.common.JSONMethodCodec;
14import io.flutter.plugin.common.MethodCall;
15import io.flutter.plugin.common.MethodChannel;
16import java.util.ArrayList;
17import java.util.Arrays;
18import java.util.List;
19import org.json.JSONArray;
20import org.json.JSONException;
21import org.json.JSONObject;
22
23/**
24 * System channel that receives requests for host platform behavior, e.g., haptic and sound effects,
25 * system chrome configurations, and clipboard interaction.
26 */
27public class PlatformChannel {
28 private static final String TAG = "PlatformChannel";
29
30 @NonNull public final MethodChannel channel;
31 @Nullable private PlatformMessageHandler platformMessageHandler;
32
33 @NonNull @VisibleForTesting
34 final MethodChannel.MethodCallHandler parsingMethodCallHandler =
36 @Override
37 public void onMethodCall(@NonNull MethodCall call, @NonNull MethodChannel.Result result) {
38 if (platformMessageHandler == null) {
39 // If no explicit PlatformMessageHandler has been registered then we don't
40 // need to forward this call to an API. Return.
41 return;
42 }
43
44 String method = call.method;
45 Object arguments = call.arguments;
46 Log.v(TAG, "Received '" + method + "' message.");
47 try {
48 switch (method) {
49 case "SystemSound.play":
50 try {
51 SoundType soundType = SoundType.fromValue((String) arguments);
52 platformMessageHandler.playSystemSound(soundType);
53 result.success(null);
54 } catch (NoSuchFieldException exception) {
55 // The desired sound type does not exist.
56 result.error("error", exception.getMessage(), null);
57 }
58 break;
59 case "HapticFeedback.vibrate":
60 try {
61 HapticFeedbackType feedbackType =
62 HapticFeedbackType.fromValue((String) arguments);
63 platformMessageHandler.vibrateHapticFeedback(feedbackType);
64 result.success(null);
65 } catch (NoSuchFieldException exception) {
66 // The desired feedback type does not exist.
67 result.error("error", exception.getMessage(), null);
68 }
69 break;
70 case "SystemChrome.setPreferredOrientations":
71 try {
72 int androidOrientation = decodeOrientations((JSONArray) arguments);
73 platformMessageHandler.setPreferredOrientations(androidOrientation);
74 result.success(null);
75 } catch (JSONException | NoSuchFieldException exception) {
76 // JSONException: One or more expected fields were either omitted or referenced an
77 // invalid type.
78 // NoSuchFieldException: One or more expected fields were either omitted or
79 // referenced an invalid type.
80 result.error("error", exception.getMessage(), null);
81 }
82 break;
83 case "SystemChrome.setApplicationSwitcherDescription":
84 try {
85 AppSwitcherDescription description =
86 decodeAppSwitcherDescription((JSONObject) arguments);
87 platformMessageHandler.setApplicationSwitcherDescription(description);
88 result.success(null);
89 } catch (JSONException exception) {
90 // One or more expected fields were either omitted or referenced an invalid type.
91 result.error("error", exception.getMessage(), null);
92 }
93 break;
94 case "SystemChrome.setEnabledSystemUIOverlays":
95 try {
96 List<SystemUiOverlay> overlays = decodeSystemUiOverlays((JSONArray) arguments);
97 platformMessageHandler.showSystemOverlays(overlays);
98 result.success(null);
99 } catch (JSONException | NoSuchFieldException exception) {
100 // JSONException: One or more expected fields were either omitted or referenced an
101 // invalid type.
102 // NoSuchFieldException: One or more of the overlay names are invalid.
103 result.error("error", exception.getMessage(), null);
104 }
105 break;
106 case "SystemChrome.setEnabledSystemUIMode":
107 try {
108 SystemUiMode mode = decodeSystemUiMode((String) arguments);
109 platformMessageHandler.showSystemUiMode(mode);
110 result.success(null);
111 } catch (JSONException | NoSuchFieldException exception) {
112 // JSONException: One or more expected fields were either omitted or referenced an
113 // invalid type.
114 // NoSuchFieldException: One or more of the overlay names are invalid.
115 result.error("error", exception.getMessage(), null);
116 }
117 break;
118 case "SystemChrome.setSystemUIChangeListener":
119 platformMessageHandler.setSystemUiChangeListener();
120 result.success(null);
121 break;
122 case "SystemChrome.restoreSystemUIOverlays":
123 platformMessageHandler.restoreSystemUiOverlays();
124 result.success(null);
125 break;
126 case "SystemChrome.setSystemUIOverlayStyle":
127 try {
128 SystemChromeStyle systemChromeStyle =
129 decodeSystemChromeStyle((JSONObject) arguments);
130 platformMessageHandler.setSystemUiOverlayStyle(systemChromeStyle);
131 result.success(null);
132 } catch (JSONException | NoSuchFieldException exception) {
133 // JSONException: One or more expected fields were either omitted or referenced an
134 // invalid type.
135 // NoSuchFieldException: One or more of the brightness names are invalid.
136 result.error("error", exception.getMessage(), null);
137 }
138 break;
139 case "SystemNavigator.setFrameworkHandlesBack":
140 {
141 boolean frameworkHandlesBack = (boolean) arguments;
142 platformMessageHandler.setFrameworkHandlesBack(frameworkHandlesBack);
143 result.success(null);
144 break;
145 }
146 case "SystemNavigator.pop":
147 platformMessageHandler.popSystemNavigator();
148 result.success(null);
149 break;
150 case "Clipboard.getData":
151 {
152 String contentFormatName = (String) arguments;
153 ClipboardContentFormat clipboardFormat = null;
154 if (contentFormatName != null) {
155 try {
156 clipboardFormat = ClipboardContentFormat.fromValue(contentFormatName);
157 } catch (NoSuchFieldException exception) {
158 // An unsupported content format was requested. Return failure.
159 result.error(
160 "error", "No such clipboard content format: " + contentFormatName, null);
161 }
162 }
163
164 CharSequence clipboardContent =
165 platformMessageHandler.getClipboardData(clipboardFormat);
166 if (clipboardContent != null) {
167 JSONObject response = new JSONObject();
168 response.put("text", clipboardContent);
169 result.success(response);
170 } else {
171 result.success(null);
172 }
173 break;
174 }
175 case "Clipboard.setData":
176 {
177 String clipboardContent = ((JSONObject) arguments).getString("text");
178 platformMessageHandler.setClipboardData(clipboardContent);
179 result.success(null);
180 break;
181 }
182 case "Clipboard.hasStrings":
183 {
184 boolean hasStrings = platformMessageHandler.clipboardHasStrings();
185 JSONObject response = new JSONObject();
186 response.put("value", hasStrings);
187 result.success(response);
188 break;
189 }
190 case "Share.invoke":
191 String text = (String) arguments;
192 platformMessageHandler.share(text);
193 result.success(null);
194 break;
195 default:
196 result.notImplemented();
197 break;
198 }
199 } catch (JSONException e) {
200 result.error("error", "JSON error: " + e.getMessage(), null);
201 }
202 }
203 };
204
205 /**
206 * Constructs a {@code PlatformChannel} that connects Android to the Dart code running in {@code
207 * dartExecutor}.
208 *
209 * <p>The given {@code dartExecutor} is permitted to be idle or executing code.
210 *
211 * <p>See {@link DartExecutor}.
212 */
213 public PlatformChannel(@NonNull DartExecutor dartExecutor) {
214 channel = new MethodChannel(dartExecutor, "flutter/platform", JSONMethodCodec.INSTANCE);
216 }
217
218 /**
219 * Sets the {@link PlatformMessageHandler} which receives all events and requests that are parsed
220 * from the underlying platform channel.
221 */
222 public void setPlatformMessageHandler(@Nullable PlatformMessageHandler platformMessageHandler) {
223 this.platformMessageHandler = platformMessageHandler;
224 }
225
226 /** Informs Flutter of a change in the SystemUI overlays. */
227 public void systemChromeChanged(boolean overlaysAreVisible) {
228 Log.v(TAG, "Sending 'systemUIChange' message.");
229 channel.invokeMethod("SystemChrome.systemUIChange", Arrays.asList(overlaysAreVisible));
230 }
231
232 // TODO(mattcarroll): add support for IntDef annotations, then add @ScreenOrientation
233
234 /**
235 * Decodes a series of orientations to an aggregate desired orientation.
236 *
237 * @throws JSONException if {@code encodedOrientations} does not contain expected keys and value
238 * types.
239 * @throws NoSuchFieldException if any given encoded orientation is not a valid orientation name.
240 */
241 private int decodeOrientations(@NonNull JSONArray encodedOrientations)
242 throws JSONException, NoSuchFieldException {
243 int requestedOrientation = 0x00;
244 int firstRequestedOrientation = 0x00;
245 for (int index = 0; index < encodedOrientations.length(); index += 1) {
246 String encodedOrientation = encodedOrientations.getString(index);
247 DeviceOrientation orientation = DeviceOrientation.fromValue(encodedOrientation);
248
249 switch (orientation) {
250 case PORTRAIT_UP:
251 requestedOrientation |= 0x01;
252 break;
253 case PORTRAIT_DOWN:
254 requestedOrientation |= 0x04;
255 break;
256 case LANDSCAPE_LEFT:
257 requestedOrientation |= 0x02;
258 break;
259 case LANDSCAPE_RIGHT:
260 requestedOrientation |= 0x08;
261 break;
262 }
263
264 if (firstRequestedOrientation == 0x00) {
265 firstRequestedOrientation = requestedOrientation;
266 }
267 }
268
269 switch (requestedOrientation) {
270 case 0x00:
271 return ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
272 case 0x01:
273 return ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
274 case 0x02:
275 return ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
276 case 0x04:
277 return ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT;
278 case 0x05:
279 return ActivityInfo.SCREEN_ORIENTATION_USER_PORTRAIT;
280 case 0x08:
281 return ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE;
282 case 0x0a:
283 return ActivityInfo.SCREEN_ORIENTATION_USER_LANDSCAPE;
284 case 0x0b:
285 return ActivityInfo.SCREEN_ORIENTATION_USER;
286 case 0x0f:
287 return ActivityInfo.SCREEN_ORIENTATION_FULL_USER;
288 case 0x03: // portraitUp and landscapeLeft
289 case 0x06: // portraitDown and landscapeLeft
290 case 0x07: // portraitUp, portraitDown, and landscapeLeft
291 case 0x09: // portraitUp and landscapeRight
292 case 0x0c: // portraitDown and landscapeRight
293 case 0x0d: // portraitUp, portraitDown, and landscapeRight
294 case 0x0e: // portraitDown, landscapeLeft, and landscapeRight
295 // Android can't describe these cases, so just default to whatever the first
296 // specified value was.
297 switch (firstRequestedOrientation) {
298 case 0x01:
299 return ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
300 case 0x02:
301 return ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
302 case 0x04:
303 return ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT;
304 case 0x08:
305 return ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE;
306 }
307 }
308
309 // Execution should never get this far, but if it does then we default
310 // to a portrait orientation.
311 return ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
312 }
313
314 @NonNull
315 private AppSwitcherDescription decodeAppSwitcherDescription(
316 @NonNull JSONObject encodedDescription) throws JSONException {
317 int color = encodedDescription.getInt("primaryColor");
318 if (color != 0) { // 0 means color isn't set, use system default
319 color = color | 0xFF000000; // color must be opaque if set
320 }
321 String label = encodedDescription.getString("label");
322 return new AppSwitcherDescription(color, label);
323 }
324
325 /**
326 * Decodes a list of JSON-encoded overlays to a list of {@link SystemUiOverlay}.
327 *
328 * @throws JSONException if {@code encodedSystemUiOverlay} does not contain expected keys and
329 * value types.
330 * @throws NoSuchFieldException if any of the given encoded overlay names are invalid.
331 */
332 @NonNull
333 private List<SystemUiOverlay> decodeSystemUiOverlays(@NonNull JSONArray encodedSystemUiOverlay)
334 throws JSONException, NoSuchFieldException {
335 List<SystemUiOverlay> overlays = new ArrayList<>();
336 for (int i = 0; i < encodedSystemUiOverlay.length(); ++i) {
337 String encodedOverlay = encodedSystemUiOverlay.getString(i);
338 SystemUiOverlay overlay = SystemUiOverlay.fromValue(encodedOverlay);
339 switch (overlay) {
340 case TOP_OVERLAYS:
341 overlays.add(SystemUiOverlay.TOP_OVERLAYS);
342 break;
343 case BOTTOM_OVERLAYS:
344 overlays.add(SystemUiOverlay.BOTTOM_OVERLAYS);
345 break;
346 }
347 }
348 return overlays;
349 }
350
351 /**
352 * Decodes an object of JSON-encoded mode to a {@link SystemUiMode}.
353 *
354 * @throws JSONException if {@code encodedSystemUiMode} does not contain expected keys and value
355 * types.
356 * @throws NoSuchFieldException if any of the given encoded mode name is invalid.
357 */
358 @NonNull
359 private SystemUiMode decodeSystemUiMode(@NonNull String encodedSystemUiMode)
360 throws JSONException, NoSuchFieldException {
361 SystemUiMode mode = SystemUiMode.fromValue(encodedSystemUiMode);
362 switch (mode) {
363 case LEAN_BACK:
364 return SystemUiMode.LEAN_BACK;
365 case IMMERSIVE:
366 return SystemUiMode.IMMERSIVE;
367 case IMMERSIVE_STICKY:
368 return SystemUiMode.IMMERSIVE_STICKY;
369 case EDGE_TO_EDGE:
370 return SystemUiMode.EDGE_TO_EDGE;
371 }
372
373 // Execution should never ever get this far, but if it does, we default to edge to edge.
374 return SystemUiMode.EDGE_TO_EDGE;
375 }
376
377 /**
378 * Decodes a JSON-encoded {@code encodedStyle} to a {@link SystemChromeStyle}.
379 *
380 * @throws JSONException if {@code encodedStyle} does not contain expected keys and value types.
381 * @throws NoSuchFieldException if any provided brightness name is invalid.
382 */
383 @NonNull
384 private SystemChromeStyle decodeSystemChromeStyle(@NonNull JSONObject encodedStyle)
385 throws JSONException, NoSuchFieldException {
386 // TODO(mattcarroll): add color annotation
387 Integer statusBarColor = null;
388 Brightness statusBarIconBrightness = null;
389 Boolean systemStatusBarContrastEnforced = null;
390 // TODO(mattcarroll): add color annotation
391 Integer systemNavigationBarColor = null;
392 Brightness systemNavigationBarIconBrightness = null;
393 // TODO(mattcarroll): add color annotation
394 Integer systemNavigationBarDividerColor = null;
395 Boolean systemNavigationBarContrastEnforced = null;
396
397 if (!encodedStyle.isNull("statusBarColor")) {
398 statusBarColor = encodedStyle.getInt("statusBarColor");
399 }
400
401 if (!encodedStyle.isNull("statusBarIconBrightness")) {
402 statusBarIconBrightness =
403 Brightness.fromValue(encodedStyle.getString("statusBarIconBrightness"));
404 }
405
406 if (!encodedStyle.isNull("systemStatusBarContrastEnforced")) {
407 systemStatusBarContrastEnforced = encodedStyle.getBoolean("systemStatusBarContrastEnforced");
408 }
409
410 if (!encodedStyle.isNull("systemNavigationBarColor")) {
411 systemNavigationBarColor = encodedStyle.getInt("systemNavigationBarColor");
412 }
413
414 if (!encodedStyle.isNull("systemNavigationBarIconBrightness")) {
415 systemNavigationBarIconBrightness =
416 Brightness.fromValue(encodedStyle.getString("systemNavigationBarIconBrightness"));
417 }
418
419 if (!encodedStyle.isNull("systemNavigationBarDividerColor")) {
420 systemNavigationBarDividerColor = encodedStyle.getInt("systemNavigationBarDividerColor");
421 }
422
423 if (!encodedStyle.isNull("systemNavigationBarContrastEnforced")) {
424 systemNavigationBarContrastEnforced =
425 encodedStyle.getBoolean("systemNavigationBarContrastEnforced");
426 }
427
428 return new SystemChromeStyle(
429 statusBarColor,
430 statusBarIconBrightness,
431 systemStatusBarContrastEnforced,
432 systemNavigationBarColor,
433 systemNavigationBarIconBrightness,
434 systemNavigationBarDividerColor,
435 systemNavigationBarContrastEnforced);
436 }
437
438 /**
439 * Handler that receives platform messages sent from Flutter to Android through a given {@link
440 * PlatformChannel}.
441 *
442 * <p>To register a {@code PlatformMessageHandler} with a {@link PlatformChannel}, see {@link
443 * PlatformChannel#setPlatformMessageHandler(PlatformMessageHandler)}.
444 */
445 public interface PlatformMessageHandler {
446 /** The Flutter application would like to play the given {@code soundType}. */
447 void playSystemSound(@NonNull SoundType soundType);
448
449 /** The Flutter application would like to play the given haptic {@code feedbackType}. */
450 void vibrateHapticFeedback(@NonNull HapticFeedbackType feedbackType);
451
452 /** The Flutter application would like to display in the given {@code androidOrientation}. */
453 // TODO(mattcarroll): add @ScreenOrientation annotation
454 void setPreferredOrientations(int androidOrientation);
455
456 /**
457 * The Flutter application would like to be displayed in Android's app switcher with the visual
458 * representation described in the given {@code description}.
459 *
460 * <p>See the related Android documentation:
461 * https://developer.android.com/guide/components/activities/recents
462 */
464
465 /**
466 * The Flutter application would like the Android system to display the given {@code overlays}.
467 *
468 * <p>{@link SystemUiOverlay#TOP_OVERLAYS} refers to system overlays such as the status bar,
469 * while {@link SystemUiOverlay#BOTTOM_OVERLAYS} refers to system overlays such as the
470 * back/home/recents navigation on the bottom of the screen.
471 *
472 * <p>An empty list of {@code overlays} should hide all system overlays.
473 */
475
476 /**
477 * The Flutter application would like the Android system to display the given {@code mode}.
478 *
479 * <p>{@link SystemUiMode#LEAN_BACK} refers to a fullscreen experience that restores system bars
480 * upon tapping anywhere in the application. This tap gesture is not received by the
481 * application.
482 *
483 * <p>{@link SystemUiMode#IMMERSIVE} refers to a fullscreen experience that restores system bars
484 * upon swiping from the edge of the viewport. This swipe gesture is not recived by the
485 * application.
486 *
487 * <p>{@link SystemUiMode#IMMERSIVE_STICKY} refers to a fullscreen experience that restores
488 * system bars upon swiping from the edge of the viewport. This swipe gesture is received by the
489 * application, in contrast to {@link SystemUiMode#IMMERSIVE}.
490 *
491 * <p>{@link SystemUiMode#EDGE_TO_EDGE} refers to a layout configuration that will consume the
492 * full viewport. This full screen experience does not hide status bars. These status bars can
493 * be set to transparent, making the buttons and icons hover over the fullscreen application.
494 */
496
497 /**
498 * The Flutter application would like the Android system to notify the framework when the system
499 * ui visibility has changed.
500 *
501 * <p>This is relevant when using {@link SystemUiMode}s for fullscreen applications, from which
502 * the system overlays can appear or disappear based on user input.
503 */
505
506 /**
507 * The Flutter application would like to restore the visibility of system overlays to the last
508 * set of overlays sent via {@link #showSystemOverlays(List)} or {@link
509 * #showSystemUiMode(SystemUiMode)}.
510 *
511 * <p>If {@link #showSystemOverlays(List)} or {@link #showSystemUiMode(SystemUiMode)} has yet to
512 * be called, then a default system overlay appearance is desired:
513 *
514 * <p>{@code View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN }
515 */
517
518 /**
519 * The Flutter application would like the system chrome to present itself with the given {@code
520 * systemUiOverlayStyle}, i.e., the given status bar and navigation bar colors and brightness.
521 */
522 void setSystemUiOverlayStyle(@NonNull SystemChromeStyle systemUiOverlayStyle);
523
524 /**
525 * The Flutter application would or would not like to handle navigation pop events itself.
526 *
527 * <p>Relevant for registering and unregistering the app's OnBackInvokedCallback for the
528 * Predictive Back feature, for example as in {@link
529 * io.flutter.embedding.android.FlutterActivity}.
530 */
531 default void setFrameworkHandlesBack(boolean frameworkHandlesBack) {}
532
533 /**
534 * The Flutter application would like to pop the top item off of the Android app's navigation
535 * back stack.
536 */
538
539 /**
540 * The Flutter application would like to receive the current data in the clipboard and have it
541 * returned in the given {@code format}.
542 */
543 @Nullable
545
546 /**
547 * The Flutter application would like to set the current data in the clipboard to the given
548 * {@code text}.
549 */
550 void setClipboardData(@NonNull String text);
551
552 /**
553 * The Flutter application would like to know if the clipboard currently contains a string that
554 * can be pasted.
555 */
557
558 /**
559 * The Flutter application would like to share the given {@code text} using the Android standard
560 * intent action named {@code Intent.ACTION_SEND}. See:
561 * https://developer.android.com/reference/android/content/Intent.html#ACTION_SEND
562 */
563 void share(@NonNull String text);
564 }
565
566 /** Types of sounds the Android OS can play on behalf of an application. */
567 public enum SoundType {
568 CLICK("SystemSoundType.click"),
569 ALERT("SystemSoundType.alert");
570
571 @NonNull
572 static SoundType fromValue(@NonNull String encodedName) throws NoSuchFieldException {
573 for (SoundType soundType : SoundType.values()) {
574 if (soundType.encodedName.equals(encodedName)) {
575 return soundType;
576 }
577 }
578 throw new NoSuchFieldException("No such SoundType: " + encodedName);
579 }
580
581 @NonNull private final String encodedName;
582
583 SoundType(@NonNull String encodedName) {
584 this.encodedName = encodedName;
585 }
586 }
587
588 /** The types of haptic feedback that the Android OS can generate on behalf of an application. */
589 public enum HapticFeedbackType {
590 STANDARD(null),
591 LIGHT_IMPACT("HapticFeedbackType.lightImpact"),
592 MEDIUM_IMPACT("HapticFeedbackType.mediumImpact"),
593 HEAVY_IMPACT("HapticFeedbackType.heavyImpact"),
594 SELECTION_CLICK("HapticFeedbackType.selectionClick");
595
596 @NonNull
597 static HapticFeedbackType fromValue(@Nullable String encodedName) throws NoSuchFieldException {
598 for (HapticFeedbackType feedbackType : HapticFeedbackType.values()) {
599 if ((feedbackType.encodedName == null && encodedName == null)
600 || (feedbackType.encodedName != null && feedbackType.encodedName.equals(encodedName))) {
601 return feedbackType;
602 }
603 }
604 throw new NoSuchFieldException("No such HapticFeedbackType: " + encodedName);
605 }
606
607 @Nullable private final String encodedName;
608
609 HapticFeedbackType(@Nullable String encodedName) {
610 this.encodedName = encodedName;
611 }
612 }
613
614 /** The possible desired orientations of a Flutter application. */
615 public enum DeviceOrientation {
616 PORTRAIT_UP("DeviceOrientation.portraitUp"),
617 PORTRAIT_DOWN("DeviceOrientation.portraitDown"),
618 LANDSCAPE_LEFT("DeviceOrientation.landscapeLeft"),
619 LANDSCAPE_RIGHT("DeviceOrientation.landscapeRight");
620
621 @NonNull
622 static DeviceOrientation fromValue(@NonNull String encodedName) throws NoSuchFieldException {
623 for (DeviceOrientation orientation : DeviceOrientation.values()) {
624 if (orientation.encodedName.equals(encodedName)) {
625 return orientation;
626 }
627 }
628 throw new NoSuchFieldException("No such DeviceOrientation: " + encodedName);
629 }
630
631 @NonNull private String encodedName;
632
633 DeviceOrientation(@NonNull String encodedName) {
634 this.encodedName = encodedName;
635 }
636 }
637
638 /**
639 * The set of Android system UI overlays as perceived by the Flutter application.
640 *
641 * <p>Android includes many more overlay options and flags than what is provided by {@code
642 * SystemUiOverlay}. Flutter only requires control over a subset of the overlays and those
643 * overlays are represented by {@code SystemUiOverlay} values.
644 */
645 public enum SystemUiOverlay {
646 TOP_OVERLAYS("SystemUiOverlay.top"),
647 BOTTOM_OVERLAYS("SystemUiOverlay.bottom");
648
649 @NonNull
650 static SystemUiOverlay fromValue(@NonNull String encodedName) throws NoSuchFieldException {
651 for (SystemUiOverlay overlay : SystemUiOverlay.values()) {
652 if (overlay.encodedName.equals(encodedName)) {
653 return overlay;
654 }
655 }
656 throw new NoSuchFieldException("No such SystemUiOverlay: " + encodedName);
657 }
658
659 @NonNull private String encodedName;
660
661 SystemUiOverlay(@NonNull String encodedName) {
662 this.encodedName = encodedName;
663 }
664 }
665
666 /** The set of Android system fullscreen modes as perceived by the Flutter application. */
667 public enum SystemUiMode {
668 LEAN_BACK("SystemUiMode.leanBack"),
669 IMMERSIVE("SystemUiMode.immersive"),
670 IMMERSIVE_STICKY("SystemUiMode.immersiveSticky"),
671 EDGE_TO_EDGE("SystemUiMode.edgeToEdge");
672
673 /**
674 * Returns the SystemUiMode for the provied encoded value. @throws NoSuchFieldException if any
675 * of the given encoded overlay names are invalid.
676 */
677 @NonNull
678 static SystemUiMode fromValue(@NonNull String encodedName) throws NoSuchFieldException {
679 for (SystemUiMode mode : SystemUiMode.values()) {
680 if (mode.encodedName.equals(encodedName)) {
681 return mode;
682 }
683 }
684 throw new NoSuchFieldException("No such SystemUiMode: " + encodedName);
685 }
686
687 @NonNull private String encodedName;
688
689 /** Returens the encoded {@link SystemUiMode} */
690 SystemUiMode(@NonNull String encodedName) {
691 this.encodedName = encodedName;
692 }
693 }
694
695 /**
696 * The color and label of an application that appears in Android's app switcher, AKA recents
697 * screen.
698 */
699 public static class AppSwitcherDescription {
700 // TODO(mattcarroll): add color annotation
701 public final int color;
702 @NonNull public final String label;
703
704 public AppSwitcherDescription(int color, @NonNull String label) {
705 this.color = color;
706 this.label = label;
707 }
708 }
709
710 /** The color and brightness of system chrome, e.g., status bar and system navigation bar. */
711 public static class SystemChromeStyle {
712 // TODO(mattcarroll): add color annotation
713 @Nullable public final Integer statusBarColor;
714 @Nullable public final Brightness statusBarIconBrightness;
715 @Nullable public final Boolean systemStatusBarContrastEnforced;
716 // TODO(mattcarroll): add color annotation
717 @Nullable public final Integer systemNavigationBarColor;
719 // TODO(mattcarroll): add color annotation
720 @Nullable public final Integer systemNavigationBarDividerColor;
721 @Nullable public final Boolean systemNavigationBarContrastEnforced;
722
724 @Nullable Integer statusBarColor,
726 @Nullable Boolean systemStatusBarContrastEnforced,
727 @Nullable Integer systemNavigationBarColor,
729 @Nullable Integer systemNavigationBarDividerColor,
730 @Nullable Boolean systemNavigationBarContrastEnforced) {
731 this.statusBarColor = statusBarColor;
732 this.statusBarIconBrightness = statusBarIconBrightness;
733 this.systemStatusBarContrastEnforced = systemStatusBarContrastEnforced;
734 this.systemNavigationBarColor = systemNavigationBarColor;
735 this.systemNavigationBarIconBrightness = systemNavigationBarIconBrightness;
736 this.systemNavigationBarDividerColor = systemNavigationBarDividerColor;
737 this.systemNavigationBarContrastEnforced = systemNavigationBarContrastEnforced;
738 }
739 }
740
741 public enum Brightness {
742 LIGHT("Brightness.light"),
743 DARK("Brightness.dark");
744
745 @NonNull
746 static Brightness fromValue(@NonNull String encodedName) throws NoSuchFieldException {
747 for (Brightness brightness : Brightness.values()) {
748 if (brightness.encodedName.equals(encodedName)) {
749 return brightness;
750 }
751 }
752 throw new NoSuchFieldException("No such Brightness: " + encodedName);
753 }
754
755 @NonNull private String encodedName;
756
757 Brightness(@NonNull String encodedName) {
758 this.encodedName = encodedName;
759 }
760 }
761
762 /** Data formats of clipboard content. */
764 PLAIN_TEXT("text/plain");
765
766 @NonNull
767 static ClipboardContentFormat fromValue(@NonNull String encodedName)
768 throws NoSuchFieldException {
770 if (format.encodedName.equals(encodedName)) {
771 return format;
772 }
773 }
774 throw new NoSuchFieldException("No such ClipboardContentFormat: " + encodedName);
775 }
776
777 @NonNull private String encodedName;
778
779 ClipboardContentFormat(@NonNull String encodedName) {
780 this.encodedName = encodedName;
781 }
782 }
783}
void add(sk_sp< SkIDChangeListener > listener) SK_EXCLUDES(fMutex)
static void v(@NonNull String tag, @NonNull String message)
Definition: Log.java:40
SystemChromeStyle( @Nullable Integer statusBarColor, @Nullable Brightness statusBarIconBrightness, @Nullable Boolean systemStatusBarContrastEnforced, @Nullable Integer systemNavigationBarColor, @Nullable Brightness systemNavigationBarIconBrightness, @Nullable Integer systemNavigationBarDividerColor, @Nullable Boolean systemNavigationBarContrastEnforced)
void setPlatformMessageHandler(@Nullable PlatformMessageHandler platformMessageHandler)
final MethodChannel.MethodCallHandler parsingMethodCallHandler
static final JSONMethodCodec INSTANCE
void setMethodCallHandler(final @Nullable MethodCallHandler handler)
void invokeMethod(@NonNull String method, @Nullable Object arguments)
DlColor color
static ClipboardContentFormat fromValue(@NonNull String encodedName)
static DeviceOrientation fromValue(@NonNull String encodedName)
static HapticFeedbackType fromValue(@Nullable String encodedName)
static SystemUiMode fromValue(@NonNull String encodedName)
static SystemUiOverlay fromValue(@NonNull String encodedName)
GAsyncResult * result
uint32_t uint32_t * format
CharSequence getClipboardData(@Nullable ClipboardContentFormat format)
void setApplicationSwitcherDescription(@NonNull AppSwitcherDescription description)
void setSystemUiOverlayStyle(@NonNull SystemChromeStyle systemUiOverlayStyle)
std::u16string text
def call(args)
Definition: dom.py:159
it will be possible to load the file into Perfetto s trace viewer disable asset Prevents usage of any non test fonts unless they were explicitly Loaded via prefetched default font Indicates whether the embedding started a prefetch of the default font manager before creating the engine run In non interactive mode
Definition: switches.h:228
#define TAG()