提交 482e63df 编写于 作者: T Todd Volkert

System chrome platform service updates (#2732)

1) Add ability to specify a system UI overlay style, to
   provide a hook into the style of the status bar icons on iOS.

2) Migrate the Activity service's task description API to the
   system chrome platform service. The old API will be removed
   once the Flutter repo is updated to use the new API after an
   engine roll.

flutter/flutter#3544
上级 6c6faf58
......@@ -22,10 +22,18 @@ class SystemChromeImpl : public SystemChrome {
uint32_t device_orientation_mask,
const SetPreferredOrientationsCallback& callback) override;
void SetApplicationSwitcherDescription(
ApplicationSwitcherDescriptionPtr description,
const SetApplicationSwitcherDescriptionCallback& callback) override;
void SetEnabledSystemUIOverlays(
uint32_t overlays,
const SetEnabledSystemUIOverlaysCallback& callback) override;
void SetSystemUIOverlayStyle(
SystemUIOverlayStyle style,
const SetSystemUIOverlayStyleCallback& callback) override;
private:
mojo::StrongBinding<SystemChrome> binding_;
......@@ -34,6 +42,8 @@ class SystemChromeImpl : public SystemChrome {
extern const char* const kOrientationUpdateNotificationName;
extern const char* const kOrientationUpdateNotificationKey;
extern const char* const kOverlayStyleUpdateNotificationName;
extern const char* const kOverlayStyleUpdateNotificationKey;
} // namespace platform
} // namespace flutter
......
......@@ -4,6 +4,7 @@
#include "sky/services/platform/ios/system_chrome_impl.h"
#include "base/mac/scoped_nsautorelease_pool.h"
#include <UIKit/UIApplication.h>
#include <UIKit/UIKit.h>
namespace flutter {
......@@ -59,8 +60,15 @@ void SystemChromeImpl::SetPreferredOrientations(
callback.Run(true);
}
void SystemChromeImpl::SetApplicationSwitcherDescription(
ApplicationSwitcherDescriptionPtr description,
const SetApplicationSwitcherDescriptionCallback& callback) {
// No counterpart on iOS but is a benign operation. So no asserts.
callback.Run(true);
}
void SystemChromeImpl::SetEnabledSystemUIOverlays(
uint32_t overlays,
uint32_t overlay_mask,
const SetEnabledSystemUIOverlaysCallback& callback) {
// Checks if the top status bar should be visible. This platform ignores all
// other overlays
......@@ -71,15 +79,56 @@ void SystemChromeImpl::SetEnabledSystemUIOverlays(
// to be able to modify this on the fly. The key used is
// UIViewControllerBasedStatusBarAppearance
[UIApplication sharedApplication].statusBarHidden =
!IsSet(overlays, SystemUIOverlay::Top);
!IsSet(overlay_mask, SystemUIOverlay::Top);
callback.Run(true);
}
void SystemChromeImpl::SetSystemUIOverlayStyle(
SystemUIOverlayStyle style,
const SetSystemUIOverlayStyleCallback& callback) {
base::mac::ScopedNSAutoreleasePool pool;
UIStatusBarStyle statusBarStyle;
switch (style) {
case SystemUIOverlayStyle::Light:
statusBarStyle = UIStatusBarStyleLightContent;
break;
case SystemUIOverlayStyle::Dark:
statusBarStyle = UIStatusBarStyleDefault;
break;
}
NSNumber* infoValue = [[NSBundle mainBundle]
objectForInfoDictionaryKey:@"UIViewControllerBasedStatusBarAppearance"];
Boolean delegateToViewController =
(infoValue == nil || [infoValue boolValue]);
if (delegateToViewController) {
// This notification is respected by the iOS embedder
[[NSNotificationCenter defaultCenter]
postNotificationName:@(kOverlayStyleUpdateNotificationName)
object:nil
userInfo:@{
@(kOverlayStyleUpdateNotificationKey) : @(statusBarStyle)
}];
} else {
// Note: -[UIApplication setStatusBarStyle] is deprecated in iOS9
// in favor of delegating to the view controller
[[UIApplication sharedApplication] setStatusBarStyle:statusBarStyle];
}
callback.Run(true);
}
const char* const kOrientationUpdateNotificationName =
"SystemChromeOrientationNotificationName";
"io.flutter.SystemChromeOrientationNotificationName";
const char* const kOrientationUpdateNotificationKey =
"SystemChromeOrientationNotificationName";
"io.flutter.SystemChromeOrientationNotificationKey";
const char* const kOverlayStyleUpdateNotificationName =
"io.flutter.SystemChromeOverlayNotificationName";
const char* const kOverlayStyleUpdateNotificationKey =
"io.flutter.SystemChromeOverlayNotificationKey";
} // namespace platform
} // namespace flutter
......@@ -6,9 +6,11 @@ package org.domokit.platform;
import android.app.Activity;
import android.content.pm.ActivityInfo;
import android.os.Build;
import android.view.View;
import org.chromium.mojo.system.MojoException;
import org.chromium.mojom.flutter.platform.ApplicationSwitcherDescription;
import org.chromium.mojom.flutter.platform.DeviceOrientation;
import org.chromium.mojom.flutter.platform.SystemChrome;
import org.chromium.mojom.flutter.platform.SystemUiOverlay;
......@@ -54,6 +56,31 @@ public class SystemChromeImpl implements SystemChrome {
callback.call(true);
}
@Override
public void setApplicationSwitcherDescription(
ApplicationSwitcherDescription description,
SetApplicationSwitcherDescriptionResponse callback) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
callback.call(true);
return;
}
int color = description.primaryColor;
if (color != 0) { // 0 means color isn't set, use system default
color = color | 0xFF000000; // color must be opaque if set
}
mActivity.setTaskDescription(
new android.app.ActivityManager.TaskDescription(
description.label,
null,
color
)
);
callback.call(true);
}
@Override
public void setEnabledSystemUiOverlays(int overlays,
SetEnabledSystemUiOverlaysResponse callback) {
......@@ -71,4 +98,12 @@ public class SystemChromeImpl implements SystemChrome {
mActivity.getWindow().getDecorView().setSystemUiVisibility(flags);
callback.call(true);
}
@Override
public void setSystemUiOverlayStyle(int style, SetSystemUiOverlayStyleResponse callback) {
// You can change the navigation bar color (including translucent colors)
// in Android, but you can't change the color of the navigation buttons,
// so LIGHT vs DARK effectively isn't supported in Android.
callback.call(true);
}
}
......@@ -39,29 +39,66 @@ enum SystemUIOverlay {
Bottom = 2,
};
/// Specifies a preference for the style of the system overlays. Certain
/// platforms may not respect this preference.
enum SystemUIOverlayStyle {
/// System overlays should be drawn with a light color. Intended for
/// applications with a dark background.
Light = 1,
/// System overlays should be drawn with a dark color. Intended for
/// applications with a light background.
Dark = 2,
};
/// Specifies a description of the application that is pertinent to the
/// embedder's application switcher (a.k.a. "recent tasks") user interface.
struct ApplicationSwitcherDescription {
/// A label and description of the current state of the application.
string? label;
/// The application's primary color.
uint32 primaryColor;
};
/// Controls specific aspects of the embedder interface.
[ServiceName="flutter::platform::SystemChrome"]
interface SystemChrome {
/// Specifies the set of orientations the application interface can
/// be displayed in.
///
/// The value 0 is synonymous with having all options enabled.
/// Arguments:
/// device_orientation_mask: A mask of `DeviceOrientation` enum values.
/// device_orientation_mask: A mask of `DeviceOrientation` enum values.
/// A value of 0 is synonymous with having all options enabled.
///
/// Return Value:
/// boolean indicating if the orientation mask is valid and the changes
/// could be conveyed successfully to the embedder.
SetPreferredOrientations(uint32 device_orientation_mask) => (bool success);
/// Specifies the description of the application within the embedder's
/// application switcher (a.k.a. "recent tasks") user interface.
///
/// Arguments:
/// description: The description of the current state of the application.
///
/// Return value:
/// boolean indicating if the preference was conveyed successfully to the
/// embedder.
///
/// Platform Specific Notes:
/// If application switcher metadata cannot be manually set on the platform,
/// specifying such metadata is a no-op and always return true.
SetApplicationSwitcherDescription(ApplicationSwitcherDescription description) => (bool success);
/// Specifies the set of overlays visible on the embedder when the
/// application is running. The embedder may choose to ignore unsupported
/// overlays
///
/// Arguments:
/// style: A mask of `SystemUIOverlay` enum values that denotes the overlays
/// to show.
/// overlay_mask: A mask of `SystemUIOverlay` enum values that denotes the
/// overlays to show. A value of 0 is synonymous with showing no
/// overlays.
///
/// Return Value:
/// boolean indicating if the preference was conveyed successfully to the
......@@ -70,5 +107,20 @@ interface SystemChrome {
/// Platform Specific Notes:
/// If the overlay is unsupported on the platform, enabling or disabling
/// that overlay is a no-op and always return true.
SetEnabledSystemUIOverlays(uint32 overlays) => (bool success);
SetEnabledSystemUIOverlays(uint32 overlay_mask) => (bool success);
/// Specifies the style of the overlays that are visible on the embedder when
/// the applicatiomn is running.
///
/// Arguments:
/// style: A `SystemUIOverlayStyle` enum value that denotes the style
///
/// Return value:
/// boolean indicating if the preference was conveyed successfully to the
/// embedder.
///
/// Platform Specific Notes:
/// If overlay style is unsupported on the platform, specifying a style is
/// a no-op and always return true.
SetSystemUIOverlayStyle(SystemUIOverlayStyle style) => (bool success);
};
......@@ -43,6 +43,7 @@ void FlutterInit(int argc, const char* argv[]) {
@implementation FlutterViewController {
base::scoped_nsprotocol<FlutterDartProject*> _dartProject;
UIInterfaceOrientationMask _orientationPreferences;
UIStatusBarStyle _statusBarStyle;
base::scoped_nsprotocol<FlutterDynamicServiceLoader*> _dynamicServiceLoader;
sky::ViewportMetricsPtr _viewportMetrics;
sky::shell::TouchMapper _touchMapper;
......@@ -87,6 +88,7 @@ void FlutterInit(int argc, const char* argv[]) {
_initialized = YES;
_orientationPreferences = UIInterfaceOrientationMaskAll;
_statusBarStyle = UIStatusBarStyleDefault;
_dynamicServiceLoader.reset([[FlutterDynamicServiceLoader alloc] init]);
_viewportMetrics = sky::ViewportMetrics::New();
_shellView =
......@@ -116,6 +118,11 @@ void FlutterInit(int argc, const char* argv[]) {
name:@(flutter::platform::kOrientationUpdateNotificationName)
object:nil];
[center addObserver:self
selector:@selector(onPreferredStatusBarStyleUpdated:)
name:@(flutter::platform::kOverlayStyleUpdateNotificationName)
object:nil];
[center addObserver:self
selector:@selector(applicationBecameActive:)
name:UIApplicationDidBecomeActiveNotification
......@@ -450,15 +457,38 @@ static inline PointerTypeMapperPhase PointerTypePhaseFromUITouchPhase(
[super viewWillDisappear:animated];
}
- (UIStatusBarStyle)preferredStatusBarStyle {
return UIStatusBarStyleLightContent;
}
- (void)dealloc {
[[NSNotificationCenter defaultCenter] removeObserver:self];
[super dealloc];
}
#pragma mark - Status bar style
- (UIStatusBarStyle)preferredStatusBarStyle {
return _statusBarStyle;
}
- (void)onPreferredStatusBarStyleUpdated:(NSNotification*)notification {
// Notifications may not be on the iOS UI thread
dispatch_async(dispatch_get_main_queue(), ^{
NSDictionary* info = notification.userInfo;
NSNumber* update =
info[@(flutter::platform::kOverlayStyleUpdateNotificationKey)];
if (update == nil) {
return;
}
NSInteger style = update.integerValue;
if (style != _statusBarStyle) {
_statusBarStyle = static_cast<UIStatusBarStyle>(style);
[self setNeedsStatusBarAppearanceUpdate];
}
});
}
#pragma mark - Application Messages
- (void)sendString:(NSString*)message withMessageName:(NSString*)messageName {
......@@ -497,14 +527,16 @@ static inline PointerTypeMapperPhase PointerTypePhaseFromUITouchPhase(
_appMessageReceiver.SetMessageListener(messageName.UTF8String, nil);
}
- (void)addAsyncMessageListener:(NSObject<FlutterAsyncMessageListener>*)listener {
- (void)addAsyncMessageListener:
(NSObject<FlutterAsyncMessageListener>*)listener {
NSAssert(listener, @"The listener must not be null");
NSString* messageName = listener.messageName;
NSAssert(messageName, @"The messageName must not be null");
_appMessageReceiver.SetAsyncMessageListener(messageName.UTF8String, listener);
}
- (void)removeAsyncMessageListener:(NSObject<FlutterAsyncMessageListener>*)listener {
- (void)removeAsyncMessageListener:
(NSObject<FlutterAsyncMessageListener>*)listener {
NSAssert(listener, @"The listener must not be null");
NSString* messageName = listener.messageName;
NSAssert(messageName, @"The messageName must not be null");
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册