提交 50f1b8d9 编写于 作者: A Adam Barth 提交者: GitHub

Remove unused services (#3128)

The platform use cases are handled by the PlatformPlugin. The media service and
the sensor service have no clients. If we want to use them, we should create
plugins for them.
上级 eb25d718
# Copyright 2015 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
import("//mojo/public/tools/bindings/mojom.gni")
group("media") {
public_deps = [
":interfaces",
]
if (is_android || is_ios) {
public_deps += [ ":media_lib" ]
}
}
mojom("interfaces") {
sources = [
"media.mojom",
]
}
if (is_android) {
import("//build/config/android/config.gni")
import("//build/config/android/rules.gni")
android_library("media_lib") {
java_files = [
"src/org/domokit/media/MediaPlayerImpl.java",
"src/org/domokit/media/MediaServiceImpl.java",
"src/org/domokit/media/SoundPoolImpl.java",
]
deps = [
"//base:base_java",
"//mojo/java",
"//mojo/public/java:bindings",
"//mojo/public/java:system",
"//flutter/services/common:common_lib",
":interfaces_java",
]
}
} else if (is_ios) {
source_set("media_lib") {
sources = [
"ios/media_player_impl.h",
"ios/media_player_impl.mm",
"ios/media_service_impl.h",
"ios/media_service_impl.mm",
"ios/sound_pool_impl.h",
"ios/sound_pool_impl.mm",
]
deps = [
":interfaces",
"//base:base",
"//mojo/data_pipe_utils",
"//mojo/public/cpp/bindings:utility",
"//mojo/public/cpp/application",
]
}
}
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef FLUTTER_SERVICES_MEDIA_IOS_MEDIA_PLAYER_IMPL_H_
#define FLUTTER_SERVICES_MEDIA_IOS_MEDIA_PLAYER_IMPL_H_
#include "base/files/file_path.h"
#include "base/macros.h"
#include "mojo/public/cpp/bindings/strong_binding.h"
#include "flutter/services/media/media.mojom.h"
#if __OBJC__
@class AudioClient;
#else // __OBJC__
class AudioClient;
#endif // __OBJC__
namespace sky {
namespace services {
namespace media {
class MediaPlayerImpl : public ::media::MediaPlayer {
public:
explicit MediaPlayerImpl(
mojo::InterfaceRequest<::media::MediaPlayer> request);
~MediaPlayerImpl() override;
void Prepare(mojo::ScopedDataPipeConsumerHandle data_source,
const ::media::MediaPlayer::PrepareCallback& callback) override;
void Start() override;
void Pause() override;
void SeekTo(uint32_t msec) override;
void SetVolume(float volume) override;
void SetLooping(bool looping) override;
private:
mojo::StrongBinding<::media::MediaPlayer> binding_;
AudioClient* audio_client_;
void onCopyToTemp(const ::media::MediaPlayer::PrepareCallback& callback,
base::FilePath path,
bool success);
void reset();
DISALLOW_COPY_AND_ASSIGN(MediaPlayerImpl);
};
} // namespace media
} // namespace services
} // namespace sky
#endif // FLUTTER_SERVICES_MEDIA_IOS_MEDIA_PLAYER_IMPL_H_
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "base/bind.h"
#include "base/message_loop/message_loop.h"
#include "mojo/data_pipe_utils/data_pipe_utils.h"
#include "flutter/services/media/ios/media_player_impl.h"
#import <Foundation/Foundation.h>
#import <AVFoundation/AVFoundation.h>
@interface AudioClient : NSObject
- (instancetype)initWithPath:(NSString*)path;
- (BOOL)play;
- (void)pause;
- (BOOL)seekTo:(NSTimeInterval)interval;
- (void)setVolume:(double)volume;
- (void)setLooping:(BOOL)loop;
+ (NSString*)temporaryFilePath;
@end
@implementation AudioClient {
AVAudioPlayer* _player;
}
- (instancetype)initWithPath:(NSString*)path {
self = [super init];
if (self) {
NSError* error = nil;
_player =
[[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL URLWithString:path]
error:&error];
if (error != nil) {
NSLog(@"Could not initialize audio client: %@",
error.localizedDescription);
[self release];
return nil;
}
}
return self;
}
- (BOOL)play {
return [_player play];
}
- (void)pause {
[_player pause];
}
- (BOOL)seekTo:(NSTimeInterval)interval {
return [_player playAtTime:_player.deviceCurrentTime + interval];
}
- (void)setVolume:(double)volume {
if (volume > 1.0) {
volume = 1.0;
}
if (volume < 0.0) {
volume = 0.0;
}
_player.volume = volume;
}
- (void)setLooping:(BOOL)shouldLoop {
_player.numberOfLoops = shouldLoop ? -1 : 0;
}
+ (NSString*)temporaryFilePath {
char temp[256] = {0};
snprintf(temp, sizeof(temp), "%smedia.XXXXXX", NSTemporaryDirectory().UTF8String);
char *path = mktemp(temp);
if (path == NULL) {
return NULL;
}
return [NSString stringWithUTF8String:path];
}
- (void)dealloc {
[_player release];
[super dealloc];
}
@end
namespace sky {
namespace services {
namespace media {
MediaPlayerImpl::MediaPlayerImpl(
mojo::InterfaceRequest<::media::MediaPlayer> request)
: binding_(this, request.Pass()), audio_client_(nullptr) {}
MediaPlayerImpl::~MediaPlayerImpl() {
reset();
}
void MediaPlayerImpl::Prepare(
mojo::ScopedDataPipeConsumerHandle data_source,
const ::media::MediaPlayer::PrepareCallback& callback) {
reset();
NSString* filePath = [AudioClient temporaryFilePath];
base::FilePath path(filePath.UTF8String);
auto taskRunner = base::MessageLoop::current()->task_runner().get();
auto copyCallback = base::Bind(&MediaPlayerImpl::onCopyToTemp,
base::Unretained(this), callback, path);
mojo::common::CopyToFile(data_source.Pass(), path, taskRunner, copyCallback);
}
void MediaPlayerImpl::onCopyToTemp(
const ::media::MediaPlayer::PrepareCallback& callback,
base::FilePath path,
bool success) {
if (success) {
NSString* filePath =
[NSString stringWithUTF8String:path.AsUTF8Unsafe().c_str()];
audio_client_ = [[AudioClient alloc] initWithPath:filePath];
} else {
reset();
}
callback.Run(success && audio_client_ != nullptr);
}
void MediaPlayerImpl::Start() {
[audio_client_ play];
}
void MediaPlayerImpl::Pause() {
[audio_client_ pause];
}
void MediaPlayerImpl::SeekTo(uint32_t msec) {
[audio_client_ seekTo:msec * 1e-3];
}
void MediaPlayerImpl::reset() {
[audio_client_ release];
audio_client_ = nullptr;
}
void MediaPlayerImpl::SetVolume(float volume) {
[audio_client_ setVolume:volume];
}
void MediaPlayerImpl::SetLooping(bool looping) {
[audio_client_ setLooping:looping];
}
} // namespace media
} // namespace services
} // namespace sky
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef FLUTTER_SERVICES_MEDIA_IOS_MEDIA_SERVICE_IMPL_H_
#define FLUTTER_SERVICES_MEDIA_IOS_MEDIA_SERVICE_IMPL_H_
#include "base/macros.h"
#include "mojo/public/cpp/bindings/strong_binding.h"
#include "flutter/services/media/media.mojom.h"
#include "flutter/services/media/ios/media_player_impl.h"
#include "flutter/services/media/ios/sound_pool_impl.h"
namespace sky {
namespace services {
namespace media {
class MediaServiceImpl : public ::media::MediaService {
public:
MediaServiceImpl(mojo::InterfaceRequest<::media::MediaService> request);
~MediaServiceImpl() override;
void CreatePlayer(
mojo::InterfaceRequest<::media::MediaPlayer> player) override;
void CreateSoundPool(mojo::InterfaceRequest<::media::SoundPool> pool,
int32_t max_streams) override;
private:
mojo::StrongBinding<::media::MediaService> binding_;
DISALLOW_COPY_AND_ASSIGN(MediaServiceImpl);
};
} // namespace media
} // namespace services
} // namespace sky
#endif // FLUTTER_SERVICES_MEDIA_IOS_MEDIA_SERVICE_IMPL_H_
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "base/logging.h"
#include "flutter/services/media/ios/media_service_impl.h"
namespace sky {
namespace services {
namespace media {
MediaServiceImpl::MediaServiceImpl(
mojo::InterfaceRequest<::media::MediaService> request)
: binding_(this, request.Pass()) {}
MediaServiceImpl::~MediaServiceImpl() {}
void MediaServiceImpl::CreatePlayer(
mojo::InterfaceRequest<::media::MediaPlayer> player) {
new MediaPlayerImpl(player.Pass());
}
void MediaServiceImpl::CreateSoundPool(
mojo::InterfaceRequest<::media::SoundPool> pool,
int32_t max_streams) {
new SoundPoolImpl(pool.Pass());
}
} // namespace media
} // namespace services
} // namespace sky
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef FLUTTER_SERVICES_MEDIA_IOS_SOUND_POOL_IMPL_H_
#define FLUTTER_SERVICES_MEDIA_IOS_SOUND_POOL_IMPL_H_
#include "base/macros.h"
#include "mojo/public/cpp/bindings/strong_binding.h"
#include "flutter/services/media/media.mojom.h"
#include "flutter/services/media/ios/media_player_impl.h"
#if __OBJC__
@class SoundPoolClient;
#else // __OBJC__
class SoundPoolClient;
#endif // __OBJC__
namespace sky {
namespace services {
namespace media {
class SoundPoolImpl : public ::media::SoundPool {
public:
explicit SoundPoolImpl(mojo::InterfaceRequest<::media::SoundPool> request);
~SoundPoolImpl() override;
void Load(mojo::ScopedDataPipeConsumerHandle data_source,
const ::media::SoundPool::LoadCallback& callback) override;
void Play(int32_t sound_id,
int32_t stream_id,
mojo::Array<float> channel_volumes,
bool loop,
float rate,
const ::media::SoundPool::PlayCallback& callback) override;
void Stop(int32_t stream_id) override;
void Pause(int32_t stream_id) override;
void Resume(int32_t stream_id) override;
void SetRate(int32_t stream_id, float rate) override;
void SetVolume(int32_t stream_id,
mojo::Array<float> channel_volumes) override;
void PauseAll() override;
void ResumeAll() override;
private:
mojo::StrongBinding<::media::SoundPool> binding_;
SoundPoolClient* sound_pool_;
std::vector<base::FilePath> temp_files_;
void onCopyToTemp(const ::media::SoundPool::LoadCallback& callback,
base::FilePath path,
bool success);
DISALLOW_COPY_AND_ASSIGN(SoundPoolImpl);
};
} // namespace media
} // namespace services
} // namespace sky
#endif // FLUTTER_SERVICES_MEDIA_IOS_SOUND_POOL_IMPL_H_
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "flutter/services/media/ios/sound_pool_impl.h"
#include "base/bind.h"
#include "base/files/file_util.h"
#include "base/mac/scoped_nsautorelease_pool.h"
#include "base/message_loop/message_loop.h"
#include "mojo/data_pipe_utils/data_pipe_utils.h"
#include <Foundation/Foundation.h>
#include <AVFoundation/AVFoundation.h>
@interface SoundPoolClient : NSObject
- (BOOL)loadPlayer:(NSURL*)url streamOut:(int32_t*)stream;
- (BOOL)play:(int32_t)stream;
- (BOOL)play:(int32_t)stream
volume:(float)volume
loop:(BOOL)loop
rate:(float)rate;
- (BOOL)resume:(int32_t)stream;
- (void)stop:(int32_t)stream;
- (void)pause:(int32_t)stream;
- (void)setRate:(float)rate stream:(int32_t)stream;
- (void)setVolume:(float)volume stream:(int32_t)stream;
- (void)pauseAll;
- (void)resumeAll;
@end
@implementation SoundPoolClient {
NSMutableDictionary* _players; // keyed by stream ID
int32_t _lastID;
}
- (instancetype)init {
self = [super init];
if (self) {
_players = [[NSMutableDictionary alloc] init];
}
return self;
}
- (BOOL)loadPlayer:(NSURL*)url streamOut:(int32_t*)stream {
if (stream == NULL) {
return NO;
}
NSError* error = NULL;
AVAudioPlayer* player =
[[AVAudioPlayer alloc] initWithContentsOfURL:url error:&error];
if (error != NULL) {
[player release];
return NO;
}
if (![player prepareToPlay]) {
[player release];
return NO;
}
int32_t streamID = ++_lastID;
_players[@(streamID)] = player;
[player release];
*stream = streamID;
return YES;
}
- (AVAudioPlayer*)playerForID:(int32_t)stream {
return _players[@(stream)];
}
- (BOOL)play:(int32_t)stream {
AVAudioPlayer *player = [self playerForID:stream];
player.currentTime = 0.0;
return [player play];
}
- (BOOL)play:(int32_t)stream
volume:(float)volume
loop:(BOOL)loop
rate:(float)rate {
AVAudioPlayer* player = [self playerForID:stream];
if (player == NULL) {
return NO;
}
if (volume > 1.0) {
volume = 1.0;
}
if (volume < 0.0) {
volume = 0.0;
}
player.volume = volume;
player.numberOfLoops = loop ? -1 : 0;
player.rate = rate;
player.currentTime = 0.0;
return [player play];
}
- (BOOL)resume:(int32_t)stream {
// Unlike a play (from beginning), we don't set the current time to 0
return [[self playerForID:stream] play];
}
- (void)stop:(int32_t)stream {
return [[self playerForID:stream] stop];
}
- (void)pause:(int32_t)stream {
return [[self playerForID:stream] pause];
}
- (void)setRate:(float)rate stream:(int32_t)stream {
[self playerForID:stream].rate = rate;
}
- (void)setVolume:(float)volume stream:(int32_t)stream {
if (volume > 1.0) {
volume = 1.0;
}
if (volume < 0.0) {
volume = 0.0;
}
[self playerForID:stream].volume = volume;
}
- (void)pauseAll {
for (AVAudioPlayer* player in [_players allValues]) {
[player pause];
}
}
- (void)resumeAll {
for (AVAudioPlayer* player in [_players allValues]) {
[player play];
}
}
- (void)dealloc {
[_players release];
[super dealloc];
}
@end
namespace sky {
namespace services {
namespace media {
SoundPoolImpl::SoundPoolImpl(mojo::InterfaceRequest<::media::SoundPool> request)
: binding_(this, request.Pass()),
sound_pool_([[SoundPoolClient alloc] init]) {}
SoundPoolImpl::~SoundPoolImpl() {
[sound_pool_ release];
for (const auto& path : temp_files_) {
base::DeleteFile(path, false);
}
}
static base::FilePath TemporaryFilePath() {
char temp[256] = {0};
NSString* tempDirectory = NSTemporaryDirectory();
snprintf(temp, sizeof(temp), "%spool.XXXXXX", tempDirectory.UTF8String);
base::FilePath path(mktemp(temp));
return path;
}
void SoundPoolImpl::Load(mojo::ScopedDataPipeConsumerHandle data_source,
const ::media::SoundPool::LoadCallback& callback) {
base::mac::ScopedNSAutoreleasePool pool;
// Copy the contents of the data source to a temporary file
auto path = TemporaryFilePath();
auto taskRunner = base::MessageLoop::current()->task_runner().get();
auto copyCallback = base::Bind(&SoundPoolImpl::onCopyToTemp,
base::Unretained(this), callback, path);
mojo::common::CopyToFile(data_source.Pass(), path, taskRunner, copyCallback);
}
void SoundPoolImpl::onCopyToTemp(
const ::media::SoundPool::LoadCallback& callback,
base::FilePath path,
bool success) {
base::mac::ScopedNSAutoreleasePool pool;
if (!success) {
callback.Run(false, 0);
return;
}
temp_files_.push_back(path);
// After the copy, initialize the audio player instance in the pool
NSString* filePath =
[NSString stringWithUTF8String:path.AsUTF8Unsafe().c_str()];
NSURL* fileURL = [NSURL URLWithString:filePath];
int32_t streamID = 0;
BOOL loadResult = [sound_pool_ loadPlayer:fileURL streamOut:&streamID];
// Fire user callback
callback.Run(loadResult, loadResult ? streamID : 0);
}
static float AverageVolume(mojo::Array<float>& channel_volumes) {
// There is no provision to set individual channel volumes. Instead, we just
// average out the volumes and pass that to the sound pool.
size_t volumesCount = channel_volumes.size();
if (volumesCount == 0) {
return 1.0;
}
float sum = 0;
for (const auto& volume : channel_volumes) {
sum += volume;
}
return sum / volumesCount;
}
void SoundPoolImpl::Play(int32_t sound_id,
int32_t stream_id,
mojo::Array<float> channel_volumes,
bool loop,
float rate,
const ::media::SoundPool::PlayCallback& callback) {
base::mac::ScopedNSAutoreleasePool pool;
// To match Android semantics, during the load operation, we return the
// ID used to key the audio player in the sound pool map as the stream ID.
// The caller is returning that ID to us as the sound ID.
BOOL playResult = [sound_pool_ play:sound_id
volume:AverageVolume(channel_volumes)
loop:loop
rate:rate];
callback.Run(playResult);
}
void SoundPoolImpl::Stop(int32_t stream_id) {
base::mac::ScopedNSAutoreleasePool pool;
[sound_pool_ stop:stream_id];
}
void SoundPoolImpl::Pause(int32_t stream_id) {
base::mac::ScopedNSAutoreleasePool pool;
[sound_pool_ pause:stream_id];
}
void SoundPoolImpl::Resume(int32_t stream_id) {
base::mac::ScopedNSAutoreleasePool pool;
[sound_pool_ resume:stream_id];
}
void SoundPoolImpl::SetRate(int32_t stream_id, float rate) {
base::mac::ScopedNSAutoreleasePool pool;
[sound_pool_ setRate:rate stream:stream_id];
}
void SoundPoolImpl::SetVolume(int32_t stream_id,
mojo::Array<float> channel_volumes) {
base::mac::ScopedNSAutoreleasePool pool;
[sound_pool_ setVolume:AverageVolume(channel_volumes) stream:stream_id];
}
void SoundPoolImpl::PauseAll() {
base::mac::ScopedNSAutoreleasePool pool;
[sound_pool_ pauseAll];
}
void SoundPoolImpl::ResumeAll() {
base::mac::ScopedNSAutoreleasePool pool;
[sound_pool_ resumeAll];
}
} // namespace media
} // namespace services
} // namespace sky
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
[DartPackage="sky_services"]
module media;
[ServiceName="media::MediaPlayer"]
interface MediaPlayer {
// ignored argument due to https://github.com/domokit/mojo/issues/282
Prepare(handle<data_pipe_consumer> data_source) => (bool ignored);
Start();
Pause();
SeekTo(uint32 msec);
SetVolume(float volume);
SetLooping(bool looping);
};
[ServiceName="media::SoundPool"]
interface SoundPool {
// Load a sound from a Mojo pipe.
Load(handle<data_pipe_consumer> data_source) =>
(bool success, int32 sound_id);
// Play a sound. The stream ID is supplied by the caller and can be used in
// other APIs to control this playback.
Play(int32 sound_id, int32 stream_id, array<float> channel_volumes, bool loop,
float rate) => (bool success);
// Stop playing a sound. After this call the stream ID is no longer valid.
Stop(int32 stream_id);
Pause(int32 stream_id);
Resume(int32 stream_id);
SetRate(int32 stream_id, float rate);
SetVolume(int32 stream_id, array<float> channel_volumes);
PauseAll();
ResumeAll();
};
[ServiceName="media::MediaService"]
interface MediaService {
CreatePlayer(MediaPlayer& player);
CreateSoundPool(SoundPool& pool, int32 max_streams);
};
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package org.domokit.media;
import android.content.Context;
import android.util.Log;
import org.chromium.mojo.common.DataPipeUtils;
import org.chromium.mojo.system.Core;
import org.chromium.mojo.system.DataPipe;
import org.chromium.mojo.system.MojoException;
import org.chromium.mojom.media.MediaPlayer;
import org.domokit.common.ResourcePaths;
import java.io.File;
import java.io.IOException;
import java.util.concurrent.Executor;
/**
* Android implementation of MediaPlayer.
*/
public class MediaPlayerImpl implements MediaPlayer, android.media.MediaPlayer.OnPreparedListener {
private static final String TAG = "MediaPlayerImpl";
private final Core mCore;
private final Context mContext;
private final Executor mExecutor;
private final android.media.MediaPlayer mPlayer;
private PrepareResponse mPrepareResponse;
private File mTempFile;
public MediaPlayerImpl(Core core, Context context, Executor executor) {
mCore = core;
mContext = context;
mExecutor = executor;
mPlayer = new android.media.MediaPlayer();
mTempFile = null;
mPrepareResponse = null;
}
@Override
public void close() {
mPlayer.release();
if (mTempFile != null) {
mTempFile.delete();
}
}
@Override
public void onConnectionError(MojoException e) {
}
@Override
public void onPrepared(android.media.MediaPlayer mp) {
assert mPlayer == mp;
assert mPrepareResponse != null;
// ignored argument due to https://github.com/domokit/mojo/issues/282
boolean ignored = true;
mPrepareResponse.call(ignored);
}
public void copyComplete() {
try {
mPlayer.setOnPreparedListener(this);
mPlayer.setDataSource(mTempFile.getCanonicalPath());
mPlayer.prepare();
} catch (java.io.IOException e) {
Log.e(TAG, "Exception", e);
mPrepareResponse.call(false);
mPrepareResponse = null;
}
}
@Override
public void prepare(DataPipe.ConsumerHandle consumerHandle, PrepareResponse callback) {
// TODO(eseidel): Ideally we'll find a way to hand the data straight
// to Android's audio system w/o first having to dump it to a file.
File outputDir = mContext.getCacheDir();
mPrepareResponse = callback;
try {
mTempFile = ResourcePaths.createTempFile(mContext, "mediaPlayer");
} catch (IOException e) {
Log.e(TAG, "Failed to create temporary file", e);
callback.call(false);
return; // TODO(eseidel): We should close the pipe?
}
DataPipeUtils.copyToFile(mCore, consumerHandle, mTempFile, mExecutor, new Runnable() {
@Override
public void run() {
copyComplete();
}
});
}
@Override
public void start() {
mPlayer.start();
}
@Override
public void seekTo(int msec) {
mPlayer.seekTo(msec);
}
@Override
public void pause() {
mPlayer.pause();
}
@Override
public void setLooping(boolean looping) {
mPlayer.setLooping(looping);
}
@Override
public void setVolume(float volume) {
mPlayer.setVolume(volume, volume);
}
}
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package org.domokit.media;
import android.content.Context;
import org.chromium.mojo.bindings.InterfaceRequest;
import org.chromium.mojo.system.Core;
import org.chromium.mojo.system.MojoException;
import org.chromium.mojom.media.MediaPlayer;
import org.chromium.mojom.media.MediaService;
import org.chromium.mojom.media.SoundPool;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* Android implementation of MediaService.
*/
public class MediaServiceImpl implements MediaService {
private final Core mCore;
private final Context mContext;
private static ExecutorService sThreadPool;
public MediaServiceImpl(Context context, Core core) {
assert context != null;
mContext = context;
assert core != null;
mCore = core;
if (sThreadPool == null) {
sThreadPool = Executors.newCachedThreadPool();
}
}
@Override
public void close() {}
@Override
public void onConnectionError(MojoException e) {}
@Override
public void createPlayer(InterfaceRequest<MediaPlayer> player) {
MediaPlayer.MANAGER.bind(new MediaPlayerImpl(mCore, mContext, sThreadPool), player);
}
@Override
public void createSoundPool(InterfaceRequest<SoundPool> pool, int maxStreams) {
SoundPool.MANAGER.bind(new SoundPoolImpl(mCore, mContext, sThreadPool, maxStreams), pool);
}
}
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package org.domokit.media;
import android.content.Context;
import android.media.AudioManager;
import android.util.Log;
import org.chromium.mojo.common.DataPipeUtils;
import org.chromium.mojo.system.Core;
import org.chromium.mojo.system.DataPipe;
import org.chromium.mojo.system.MojoException;
import org.chromium.mojom.media.SoundPool;
import org.domokit.common.ResourcePaths;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.concurrent.Executor;
/**
* Mojo service providing access to SoundPool.
*/
public class SoundPoolImpl implements SoundPool, android.media.SoundPool.OnLoadCompleteListener {
private static final String TAG = "SoundPoolImpl";
private final Core mCore;
private final Context mContext;
private final Executor mExecutor;
private final android.media.SoundPool mSoundPool;
private final ArrayList<File> mTempFiles;
private final HashMap<Integer, LoadResponse> mPendingLoads;
// Maps stream IDs provided by the client to stream IDs assigned by the Android SoundPool.
private final HashMap<Integer, Integer> mStreamIdMap;
public SoundPoolImpl(Core core, Context context, Executor executor, int maxStreams) {
mCore = core;
mContext = context;
mExecutor = executor;
mTempFiles = new ArrayList<File>();
mPendingLoads = new HashMap<Integer, LoadResponse>();
mStreamIdMap = new HashMap<Integer, Integer>();
android.media.SoundPool.Builder builder = new android.media.SoundPool.Builder();
builder.setMaxStreams(maxStreams);
mSoundPool = builder.build();
mSoundPool.setOnLoadCompleteListener(this);
}
@Override
public void close() {
if (mSoundPool != null) {
mSoundPool.release();
}
for (File tempFile : mTempFiles) {
tempFile.delete();
}
}
@Override
public void onConnectionError(MojoException e) {
}
@Override
public void load(DataPipe.ConsumerHandle consumerHandle, final LoadResponse callback) {
File file;
try {
file = ResourcePaths.createTempFile(mContext, "soundPool");
} catch (IOException e) {
Log.e(TAG, "Failed to create temporary file", e);
callback.call(false, 0);
return;
}
final File tempFile = file;
mTempFiles.add(tempFile);
DataPipeUtils.copyToFile(mCore, consumerHandle, tempFile, mExecutor, new Runnable() {
@Override
public void run() {
String path;
try {
path = tempFile.getCanonicalPath();
} catch (IOException e) {
callback.call(false, 0);
return;
}
int soundId = mSoundPool.load(path, 1);
mPendingLoads.put(soundId, callback);
}
});
}
@Override
public void onLoadComplete(android.media.SoundPool soundPool, int soundId, int status) {
LoadResponse callback = mPendingLoads.remove(soundId);
if (callback != null) {
callback.call(true, soundId);
}
}
@Override
public void play(int soundId, int streamId, float[] channelVolumes, boolean loop, float rate,
PlayResponse callback) {
if (channelVolumes.length != 2) {
Log.e(TAG, "setVolume: channelVolumes must be of length 2");
callback.call(false);
return;
}
int poolStreamId = mSoundPool.play(soundId,
channelVolumes[0], channelVolumes[1],
0, loop ? -1 : 0, rate);
if (poolStreamId != 0) {
mStreamIdMap.put(streamId, poolStreamId);
callback.call(true);
} else {
callback.call(false);
}
}
@Override
public void stop(int streamId) {
Integer poolStreamId = mStreamIdMap.remove(streamId);
if (poolStreamId != null) {
mSoundPool.stop(poolStreamId);
}
}
@Override
public void pause(int streamId) {
Integer poolStreamId = mStreamIdMap.get(streamId);
if (poolStreamId != null) {
mSoundPool.pause(poolStreamId);
}
}
@Override
public void resume(int streamId) {
Integer poolStreamId = mStreamIdMap.get(streamId);
if (poolStreamId != null) {
mSoundPool.resume(poolStreamId);
}
}
@Override
public void setRate(int streamId, float rate) {
Integer poolStreamId = mStreamIdMap.get(streamId);
if (poolStreamId != null) {
mSoundPool.setRate(poolStreamId, rate);
}
}
@Override
public void setVolume(int streamId, float[] channelVolumes) {
if (channelVolumes.length != 2) {
Log.e(TAG, "setVolume: channelVolumes must be of length 2");
return;
}
Integer poolStreamId = mStreamIdMap.get(streamId);
if (poolStreamId != null) {
mSoundPool.setVolume(poolStreamId, channelVolumes[0], channelVolumes[1]);
}
}
@Override
public void pauseAll() {
mSoundPool.autoPause();
}
@Override
public void resumeAll() {
mSoundPool.autoResume();
}
}
......@@ -7,65 +7,11 @@ import("//mojo/public/tools/bindings/mojom.gni")
mojom("interfaces") {
sources = [
"app_messages.mojom",
"haptic_feedback.mojom",
"path_provider.mojom",
"system_chrome.mojom",
"system_sound.mojom",
"url_launcher.mojom",
]
}
if (is_android) {
import("//build/config/android/config.gni")
import("//build/config/android/rules.gni")
android_library("platform_lib") {
java_files = [
"src/org/domokit/platform/HapticFeedbackImpl.java",
"src/org/domokit/platform/PathProviderImpl.java",
"src/org/domokit/platform/SystemChromeImpl.java",
"src/org/domokit/platform/SystemSoundImpl.java",
"src/org/domokit/platform/UrlLauncherImpl.java",
]
deps = [
"//base:base_java",
"//mojo/public/java:bindings",
"//mojo/public/java:system",
"//flutter/services/common:common_lib",
":interfaces_java",
]
}
}
if (is_ios) {
source_set("platform_lib") {
sources = [
"ios/haptic_feedback_impl.h",
"ios/haptic_feedback_impl.mm",
"ios/path_provider_impl.h",
"ios/path_provider_impl.mm",
"ios/system_chrome_impl.h",
"ios/system_chrome_impl.mm",
"ios/system_sound_impl.h",
"ios/system_sound_impl.mm",
"ios/url_launcher_impl.h",
"ios/url_launcher_impl.mm",
]
deps = [
"//base:base",
"//mojo/public/cpp/bindings:utility",
"//mojo/public/cpp/application",
":interfaces",
]
}
}
group("platform") {
public_deps = [
":interfaces"
]
if (is_android || is_ios) {
public_deps += [ ":platform_lib" ]
}
}
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
[DartPackage="sky_services"]
module flutter.platform;
/// Allows access to the haptic feedback interface on the device. This API is
/// intentionally terse since it invokes default platform behavior. It is not
/// suitable for use if you require more flexible access to device sensors and
/// peripherals.
[ServiceName="flutter::platform::HapticFeedback"]
interface HapticFeedback {
/// Provides haptic feedback to the user for a short duration.
///
/// Platform Specific Notes:
/// iOS: Uses the platform "sound" for vibration
/// (via AudioServicesPlaySystemSound)
/// Android: Uses the platform haptic feedback API that simulates a short
/// a short tap on a virtual keyboard.
///
/// Return Value:
/// boolean indicating if the intent to provide haptic feedback to the user
/// was successfully conveyed to the embedder. There may not be any actual
/// feedback if the device does not have a vibrator or one is disabled in
/// system settings.
Vibrate() => (bool success);
};
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef FLUTTER_SERVICES_PLATFORM_IOS_HAPTIC_FEEDBACK_IMPL_H_
#define FLUTTER_SERVICES_PLATFORM_IOS_HAPTIC_FEEDBACK_IMPL_H_
#include "base/macros.h"
#include "mojo/public/cpp/bindings/strong_binding.h"
#include "flutter/services/platform/haptic_feedback.mojom.h"
namespace flutter {
namespace platform {
class HapticFeedbackImpl : public HapticFeedback {
public:
explicit HapticFeedbackImpl(mojo::InterfaceRequest<HapticFeedback> request);
~HapticFeedbackImpl() override;
void Vibrate(const VibrateCallback& callback) override;
private:
mojo::StrongBinding<HapticFeedback> binding_;
DISALLOW_COPY_AND_ASSIGN(HapticFeedbackImpl);
};
} // namespace platform
} // namespace flutter
#endif // FLUTTER_SERVICES_PLATFORM_IOS_HAPTIC_FEEDBACK_IMPL_H_
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "flutter/services/platform/ios/haptic_feedback_impl.h"
#include <AudioToolbox/AudioToolbox.h>
namespace flutter {
namespace platform {
HapticFeedbackImpl::HapticFeedbackImpl(
mojo::InterfaceRequest<HapticFeedback> request)
: binding_(this, request.Pass()) {}
HapticFeedbackImpl::~HapticFeedbackImpl() {}
void HapticFeedbackImpl::Vibrate(const VibrateCallback& callback) {
AudioServicesPlayAlertSound(kSystemSoundID_Vibrate);
}
} // namespace platform
} // namespace flutter
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef FLUTTER_SERVICES_PLATFORM_IOS_PATH_PROVIDER_IMPL_H_
#define FLUTTER_SERVICES_PLATFORM_IOS_PATH_PROVIDER_IMPL_H_
#include "base/macros.h"
#include "mojo/public/cpp/bindings/strong_binding.h"
#include "flutter/services/platform/path_provider.mojom.h"
namespace flutter {
namespace platform {
class PathProviderImpl : public PathProvider {
public:
explicit PathProviderImpl(mojo::InterfaceRequest<PathProvider> request);
~PathProviderImpl() override;
void TemporaryDirectory(const TemporaryDirectoryCallback& callback) override;
void ApplicationDocumentsDirectory(
const ApplicationDocumentsDirectoryCallback& callback) override;
private:
mojo::StrongBinding<PathProvider> binding_;
DISALLOW_COPY_AND_ASSIGN(PathProviderImpl);
};
} // namespace platform
} // namespace flutter
#endif // FLUTTER_SERVICES_PLATFORM_IOS_PATH_PROVIDER_IMPL_H_
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "flutter/services/platform/ios/path_provider_impl.h"
#include "base/mac/scoped_nsautorelease_pool.h"
#include <Foundation/Foundation.h>
#include <string>
namespace flutter {
namespace platform {
PathProviderImpl::PathProviderImpl(mojo::InterfaceRequest<PathProvider> request)
: binding_(this, request.Pass()) {}
PathProviderImpl::~PathProviderImpl() {}
static std::string GetDirectoryOfType(NSSearchPathDirectory dir) {
base::mac::ScopedNSAutoreleasePool pool;
NSArray* paths =
NSSearchPathForDirectoriesInDomains(dir, NSUserDomainMask, YES);
if (paths.count == 0) {
return "";
}
return [paths.firstObject UTF8String];
}
void PathProviderImpl::TemporaryDirectory(
const TemporaryDirectoryCallback& callback) {
callback.Run(GetDirectoryOfType(NSCachesDirectory));
}
void PathProviderImpl::ApplicationDocumentsDirectory(
const ApplicationDocumentsDirectoryCallback& callback) {
callback.Run(GetDirectoryOfType(NSDocumentDirectory));
}
} // namespace platform
} // namespace flutter
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef FLUTTER_SERVICES_PLATFORM_IOS_SYSTEM_CHROME_IMPL_H_
#define FLUTTER_SERVICES_PLATFORM_IOS_SYSTEM_CHROME_IMPL_H_
#include "base/macros.h"
#include "mojo/public/cpp/bindings/strong_binding.h"
#include "flutter/services/platform/system_chrome.mojom.h"
namespace flutter {
namespace platform {
class SystemChromeImpl : public SystemChrome {
public:
explicit SystemChromeImpl(mojo::InterfaceRequest<SystemChrome> request);
~SystemChromeImpl() override;
void SetPreferredOrientations(
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_;
DISALLOW_COPY_AND_ASSIGN(SystemChromeImpl);
};
extern const char* const kOrientationUpdateNotificationName;
extern const char* const kOrientationUpdateNotificationKey;
extern const char* const kOverlayStyleUpdateNotificationName;
extern const char* const kOverlayStyleUpdateNotificationKey;
} // namespace platform
} // namespace flutter
#endif // FLUTTER_SERVICES_PLATFORM_IOS_SYSTEM_CHROME_IMPL_H_
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "flutter/services/platform/ios/system_chrome_impl.h"
#include "base/mac/scoped_nsautorelease_pool.h"
#include <UIKit/UIApplication.h>
#include <UIKit/UIKit.h>
namespace flutter {
namespace platform {
SystemChromeImpl::SystemChromeImpl(mojo::InterfaceRequest<SystemChrome> request)
: binding_(this, request.Pass()) {}
SystemChromeImpl::~SystemChromeImpl() {}
/// Desugars a typed enum value and checks if it is set in a mask
template <class T,
class = typename std::enable_if<std::is_enum<T>::value>::type>
static constexpr bool IsSet(uint32_t mask, T orientation) {
return (static_cast<int32_t>(orientation) & mask) != 0;
}
void SystemChromeImpl::SetPreferredOrientations(
uint32_t device_mask,
const SetPreferredOrientationsCallback& callback) {
UIInterfaceOrientationMask mask = 0;
if (device_mask == 0) {
mask |= UIInterfaceOrientationMaskAll;
}
if (IsSet(device_mask, DeviceOrientation::PortraitUp)) {
mask |= UIInterfaceOrientationMaskPortrait;
}
if (IsSet(device_mask, DeviceOrientation::PortraitDown)) {
mask |= UIInterfaceOrientationMaskPortraitUpsideDown;
}
if (IsSet(device_mask, DeviceOrientation::LandscapeLeft)) {
mask |= UIInterfaceOrientationMaskLandscapeLeft;
}
if (IsSet(device_mask, DeviceOrientation::LandscapeRight)) {
mask |= UIInterfaceOrientationMaskLandscapeRight;
}
if (mask == 0) {
// An impossible configuration was requested. Bail.
callback.Run(false);
return;
}
base::mac::ScopedNSAutoreleasePool pool;
// This notification is respected by the iOS embedder
[[NSNotificationCenter defaultCenter]
postNotificationName:@(kOrientationUpdateNotificationName)
object:nil
userInfo:@{
@(kOrientationUpdateNotificationKey) : @(mask)
}];
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 overlay_mask,
const SetEnabledSystemUIOverlaysCallback& callback) {
// Checks if the top status bar should be visible. This platform ignores all
// other overlays
base::mac::ScopedNSAutoreleasePool pool;
// We opt out of view controller based status bar visibility since we want
// to be able to modify this on the fly. The key used is
// UIViewControllerBasedStatusBarAppearance
[UIApplication sharedApplication].statusBarHidden =
!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 =
"io.flutter.SystemChromeOrientationNotificationName";
const char* const kOrientationUpdateNotificationKey =
"io.flutter.SystemChromeOrientationNotificationKey";
const char* const kOverlayStyleUpdateNotificationName =
"io.flutter.SystemChromeOverlayNotificationName";
const char* const kOverlayStyleUpdateNotificationKey =
"io.flutter.SystemChromeOverlayNotificationKey";
} // namespace platform
} // namespace flutter
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef FLUTTER_SERVICES_PLATFORM_IOS_SYSTEM_SOUND_IMPL_H_
#define FLUTTER_SERVICES_PLATFORM_IOS_SYSTEM_SOUND_IMPL_H_
#include "base/macros.h"
#include "mojo/public/cpp/bindings/strong_binding.h"
#include "flutter/services/platform/system_sound.mojom.h"
namespace flutter {
namespace platform {
class SystemSoundImpl : public SystemSound {
public:
explicit SystemSoundImpl(mojo::InterfaceRequest<SystemSound> request);
~SystemSoundImpl() override;
void Play(SystemSoundType type, const PlayCallback& callback) override;
private:
mojo::StrongBinding<SystemSound> binding_;
DISALLOW_COPY_AND_ASSIGN(SystemSoundImpl);
};
} // namespace platform
} // namespace flutter
#endif // FLUTTER_SERVICES_PLATFORM_IOS_SYSTEM_SOUND_IMPL_H_
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "flutter/services/platform/ios/system_sound_impl.h"
#include "base/mac/scoped_nsautorelease_pool.h"
#include <UIKit/UIKit.h>
namespace flutter {
namespace platform {
SystemSoundImpl::SystemSoundImpl(mojo::InterfaceRequest<SystemSound> request)
: binding_(this, request.Pass()) {}
SystemSoundImpl::~SystemSoundImpl() {}
void SystemSoundImpl::Play(SystemSoundType type, const PlayCallback& callback) {
base::mac::ScopedNSAutoreleasePool pool;
switch (type) {
case SystemSoundType::Click:
// All feedback types are specific to Android and are treated as equal on
// iOS. The surface must (and does) adopt the UIInputViewAudioFeedback
// protocol
[[UIDevice currentDevice] playInputClick];
callback.Run(true);
return;
// Add more system types here as they are introduced
}
callback.Run(false);
}
} // namespace platform
} // namespace flutter
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef FLUTTER_SERVICES_PLATFORM_IOS_URL_LAUNCHER_IMPL_H_
#define FLUTTER_SERVICES_PLATFORM_IOS_URL_LAUNCHER_IMPL_H_
#include "base/macros.h"
#include "mojo/public/cpp/bindings/strong_binding.h"
#include "flutter/services/platform/url_launcher.mojom.h"
namespace flutter {
namespace platform {
class URLLauncherImpl : public URLLauncher {
public:
explicit URLLauncherImpl(mojo::InterfaceRequest<URLLauncher> request);
~URLLauncherImpl() override;
void Launch(const mojo::String& uriString,
const LaunchCallback& callback) override;
private:
mojo::StrongBinding<URLLauncher> binding_;
DISALLOW_COPY_AND_ASSIGN(URLLauncherImpl);
};
} // namespace platform
} // namespace flutter
#endif // FLUTTER_SERVICES_PLATFORM_IOS_URL_LAUNCHER_IMPL_H_
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "flutter/services/platform/ios/url_launcher_impl.h"
#include "base/mac/scoped_nsautorelease_pool.h"
#include <UIKit/UIKit.h>
namespace flutter {
namespace platform {
URLLauncherImpl::URLLauncherImpl(mojo::InterfaceRequest<URLLauncher> request)
: binding_(this, request.Pass()) {}
URLLauncherImpl::~URLLauncherImpl() {}
void URLLauncherImpl::Launch(const mojo::String& urlString,
const LaunchCallback& callback) {
base::mac::ScopedNSAutoreleasePool pool;
NSURL* url = [NSURL URLWithString:@(urlString.data())];
UIApplication* application = [UIApplication sharedApplication];
return callback.Run([application canOpenURL:url] &&
[application openURL:url]);
}
} // namespace platform
} // namespace flutter
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
[DartPackage="sky_services"]
module flutter.platform;
/// Returns commonly used locations on the filesystem.
[ServiceName="flutter::platform::PathProvider"]
interface PathProvider {
/// Path to the temporary directory on the device. Files in this directory
/// may be cleared at any time. This does *not* return a new temporary
/// directory. Instead, the caller is responsible for creating
/// (and cleaning up) files or directories within this directory. This
/// directory is scoped to the calling application.
///
/// Example(s):
/// iOS: `NSTemporaryDirectory()`
/// Android: `getCacheDir()` on the context.
TemporaryDirectory() => (string path);
/// Path to a directory where the application may place files that are private
/// to the application and will only be cleared when the application itself
/// is deleted.
///
/// Example(s):
/// iOS: `NSDocumentsDirectory`
/// Android: The AppData directory.
ApplicationDocumentsDirectory() => (string path);
};
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package org.domokit.platform;
import android.app.Activity;
import android.view.HapticFeedbackConstants;
import android.view.View;
import org.chromium.mojo.system.MojoException;
import org.chromium.mojom.flutter.platform.HapticFeedback;
/**
* Android implementation of HapticFeedback.
*/
public class HapticFeedbackImpl implements HapticFeedback {
private final Activity mActivity;
public HapticFeedbackImpl(Activity activity) {
mActivity = activity;
}
@Override
public void close() {}
@Override
public void onConnectionError(MojoException e) {}
@Override
public void vibrate(VibrateResponse callback) {
View view = mActivity.getWindow().getDecorView();
view.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
callback.call(true);
}
}
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package org.domokit.platform;
import android.content.Context;
import org.chromium.base.PathUtils;
import org.chromium.mojo.system.MojoException;
import org.chromium.mojom.flutter.platform.PathProvider;
/**
* Android implementation of PathProvider.
*/
public class PathProviderImpl implements PathProvider {
private final Context mContext;
public PathProviderImpl(Context context) {
mContext = context;
}
@Override
public void close() {}
@Override
public void onConnectionError(MojoException e) {}
@Override
public void temporaryDirectory(TemporaryDirectoryResponse callback) {
callback.call(mContext.getCacheDir().getPath());
}
@Override
public void applicationDocumentsDirectory(ApplicationDocumentsDirectoryResponse callback) {
callback.call(PathUtils.getDataDirectory(mContext));
}
}
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
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;
import org.domokit.common.ActivityLifecycleListener;
/**
* Android implementation of SystemChrome.
*/
public class SystemChromeImpl implements SystemChrome, ActivityLifecycleListener {
private final Activity mActivity;
private int mEnabledOverlays;
public SystemChromeImpl(Activity activity) {
mActivity = activity;
mEnabledOverlays = SystemUiOverlay.TOP | SystemUiOverlay.BOTTOM;
}
@Override
public void close() {}
@Override
public void onConnectionError(MojoException e) {}
@Override
public void setPreferredOrientations(int deviceOrientationMask,
SetPreferredOrientationsResponse callback) {
// Currently the Android implementation only supports masks with zero or one
// selected device orientations.
int androidOrientation;
if (deviceOrientationMask == 0) {
androidOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
} else if (deviceOrientationMask == DeviceOrientation.PORTRAIT_UP) {
androidOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
} else if (deviceOrientationMask == DeviceOrientation.LANDSCAPE_LEFT) {
androidOrientation = ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
} else if (deviceOrientationMask == DeviceOrientation.PORTRAIT_DOWN) {
androidOrientation = ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT;
} else if (deviceOrientationMask == DeviceOrientation.LANDSCAPE_RIGHT) {
androidOrientation = ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE;
} else {
callback.call(false);
return;
}
mActivity.setRequestedOrientation(androidOrientation);
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) {
mEnabledOverlays = overlays;
updateSystemUiOverlays();
callback.call(true);
}
private void updateSystemUiOverlays() {
int flags = View.SYSTEM_UI_FLAG_LAYOUT_STABLE |
View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
if ((mEnabledOverlays & SystemUiOverlay.TOP) == 0) {
flags |= View.SYSTEM_UI_FLAG_FULLSCREEN;
}
if ((mEnabledOverlays & SystemUiOverlay.BOTTOM) == 0) {
flags |= View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION |
View.SYSTEM_UI_FLAG_HIDE_NAVIGATION;
}
if (mEnabledOverlays == 0) {
flags |= View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY;
}
mActivity.getWindow().getDecorView().setSystemUiVisibility(flags);
}
@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);
}
@Override
public void onPostResume() {
updateSystemUiOverlays();
}
}
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package org.domokit.platform;
import android.app.Activity;
import android.view.SoundEffectConstants;
import android.view.View;
import org.chromium.mojo.system.MojoException;
import org.chromium.mojom.flutter.platform.SystemSound;
import org.chromium.mojom.flutter.platform.SystemSoundType;
/**
* Android implementation of SystemSound.
*/
public class SystemSoundImpl implements SystemSound {
private final Activity mActivity;
public SystemSoundImpl(Activity activity) {
mActivity = activity;
}
@Override
public void close() {}
@Override
public void onConnectionError(MojoException e) {}
@Override
public void play(int type, PlayResponse callback) {
if (type != SystemSoundType.CLICK) {
callback.call(false);
return;
}
View view = mActivity.getWindow().getDecorView();
view.playSoundEffect(SoundEffectConstants.CLICK);
callback.call(true);
}
}
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package org.domokit.platform;
import android.app.Activity;
import android.content.Intent;
import android.net.Uri;
import org.chromium.mojo.system.MojoException;
import org.chromium.mojom.flutter.platform.UrlLauncher;
/**
* Android implementation of UrlLauncher.
*/
public class UrlLauncherImpl implements UrlLauncher {
private final Activity mActivity;
public UrlLauncherImpl(Activity activity) {
mActivity = activity;
}
@Override
public void close() {}
@Override
public void onConnectionError(MojoException e) {}
@Override
public void launch(String urlString, LaunchResponse callback) {
try {
Intent launchIntent = new Intent(Intent.ACTION_VIEW);
launchIntent.setData(Uri.parse(urlString));
mActivity.startActivity(launchIntent);
callback.call(true);
} catch (java.lang.Exception exception) {
// In case of parsing or ActivityNotFound errors
callback.call(false);
}
}
}
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
[DartPackage="sky_services"]
module flutter.platform;
/// Specifies a particular device orientation. A mask of device interface
/// orientations is created by or'ing individual options.
///
/// Discussion:
/// To determine which values correspond to which orientations, first position
/// the device in its default orientation (this is the orientation that the
/// system first uses for its boot logo, or the orientation in which the
/// hardware logos or markings are upright, or the orientation in which the
/// cameras are at the top). If this is a portrait orientation, then this is
/// PortraitUp. Otherwise, it's LandscapeLeft. As you rotate the device by 90
/// degrees in a counter-clockwise direction around the axis that traverses the
/// screen, you step through each value in this enum in the order given. (For a
/// device with a landscape default orientation, the orientation obtained by
/// rotating the device 90 degrees clockwise from its default orientation is
/// PortraitUp.)
enum /* options*/ DeviceOrientation {
PortraitUp = 1,
LandscapeLeft = 2,
PortraitDown = 4,
LandscapeRight = 8,
};
/// Specifies a system overlay at a particular location. Certain platforms
/// may not use all overlays specified here.
enum SystemUIOverlay {
/// The status bar provided by the embedder on the top of the application
/// surface (optional)
Top = 1,
/// The status bar provided by the embedder on the bottom of the application
/// surface (optional)
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.
///
/// Arguments:
/// 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:
/// 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
/// embedder.
///
/// 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 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);
};
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
[DartPackage="sky_services"]
module flutter.platform;
/// A sound provided by the system
enum SystemSoundType {
Click,
};
/// Allows easy access to the library of short system specific sounds for
/// common tasks.
[ServiceName="flutter::platform::SystemSound"]
interface SystemSound {
/// Play the specified system sound. If that sound is not present on the
/// system, this method is a no-op and returns `true`.
///
/// Return Value:
/// boolean indicating if the intent to play the specified sound was
/// successfully conveyed to the embedder. No sound may actually play if the
/// device is muted or the sound was not available on the platform.
Play(SystemSoundType type) => (bool success);
};
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
[DartPackage="sky_services"]
module flutter.platform;
/// Allows applications to delegate responsbility of handling certain URLs to
/// the underlying platform.
[ServiceName="flutter::platform::URLLauncher"]
interface URLLauncher {
/// Parse the specified URL string and delegate handling of the same to the
/// underlying platform.
///
/// Return Value:
/// boolean indicating if the intent to handle the URL was successfully
/// conveyed to the to underlying platform and the platform could
/// successfully handle the same. The platform is responsible for URL
/// parsing.
Launch(string urlString) => (bool success);
};
# Copyright 2015 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
if (is_android) {
import("//build/config/android/config.gni")
import("//mojo/android/rules.gni")
mojo_android_java_application("sensors") {
sources = [
"src/org/chromium/mojo/sensors/Sensors.java",
]
mojo_main = "org.chromium.mojo.sensors.Sensors"
deps = [
":sensors_lib",
"//mojo/public/interfaces/application:application_java",
"//mojo/public/java:application",
"//mojo/services/sensors/interfaces:interfaces_java",
]
}
android_library("sensors_lib") {
java_files = [
"src/org/chromium/mojo/sensors/SensorForwarder.java",
"src/org/chromium/mojo/sensors/SensorServiceImpl.java",
]
deps = [
"//mojo/public/java:bindings",
"//mojo/public/java:system",
"//mojo/services/sensors/interfaces:interfaces_java",
]
}
}
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package org.chromium.mojo.sensors;
import android.content.Context;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.util.Log;
import org.chromium.mojo.bindings.ConnectionErrorHandler;
import org.chromium.mojo.system.MojoException;
import org.chromium.mojom.sensors.SensorData;
import org.chromium.mojom.sensors.SensorListener;
import org.chromium.mojom.sensors.SensorType;
/**
* A class to forward sensor data to a SensorListener.
*/
public class SensorForwarder implements ConnectionErrorHandler, SensorEventListener {
private static final String TAG = "SensorForwarder";
private SensorListener.Proxy mListener;
private SensorManager mManager;
private Sensor mSensor;
private static int getAndroidTypeForSensor(int sensorType) {
switch (sensorType) {
case SensorType.ACCELEROMETER:
return Sensor.TYPE_ACCELEROMETER;
case SensorType.AMBIENT_TEMPERATURE:
return Sensor.TYPE_AMBIENT_TEMPERATURE;
case SensorType.GAME_ROTATION_VECTOR:
return Sensor.TYPE_GAME_ROTATION_VECTOR;
case SensorType.GEOMAGNETIC_ROTATION_VECTOR:
return Sensor.TYPE_GEOMAGNETIC_ROTATION_VECTOR;
case SensorType.GRAVITY:
return Sensor.TYPE_GRAVITY;
case SensorType.GYROSCOPE:
return Sensor.TYPE_GYROSCOPE;
case SensorType.GYROSCOPE_UNCALIBRATED:
return Sensor.TYPE_GYROSCOPE_UNCALIBRATED;
case SensorType.HEART_RATE:
return Sensor.TYPE_HEART_RATE;
case SensorType.LIGHT:
return Sensor.TYPE_LIGHT;
case SensorType.LINEAR_ACCELERATION:
return Sensor.TYPE_LINEAR_ACCELERATION;
case SensorType.MAGNETIC_FIELD:
return Sensor.TYPE_MAGNETIC_FIELD;
case SensorType.MAGNETIC_FIELD_UNCALIBRATED:
return Sensor.TYPE_MAGNETIC_FIELD_UNCALIBRATED;
case SensorType.PRESSURE:
return Sensor.TYPE_PRESSURE;
case SensorType.PROXIMITY:
return Sensor.TYPE_PROXIMITY;
case SensorType.RELATIVE_HUMIDITY:
return Sensor.TYPE_RELATIVE_HUMIDITY;
case SensorType.ROTATION_VECTOR:
return Sensor.TYPE_ROTATION_VECTOR;
case SensorType.SIGNIFICANT_MOTION:
return Sensor.TYPE_SIGNIFICANT_MOTION;
case SensorType.STEP_COUNTER:
return Sensor.TYPE_STEP_COUNTER;
case SensorType.STEP_DETECTOR:
return Sensor.TYPE_STEP_DETECTOR;
default:
return -1;
}
}
public SensorForwarder(Context context, int mojoSensorType, SensorListener.Proxy listener) {
int androidSensorType = getAndroidTypeForSensor(mojoSensorType);
mListener = listener;
mManager = (SensorManager) context.getSystemService(Context.SENSOR_SERVICE);
mSensor = mManager.getDefaultSensor(androidSensorType);
if (mSensor == null) {
Log.e(TAG, "No default sensor for sensor type " + mojoSensorType);
mListener.close();
return;
}
// TODO(abarth): We should expose a way for clients to request different
// update rates.
mManager.registerListener(this, mSensor, SensorManager.SENSOR_DELAY_NORMAL);
mListener.getProxyHandler().setErrorHandler(this);
}
@Override
public void onConnectionError(MojoException e) {
mManager.unregisterListener(this);
}
@Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
mListener.onAccuracyChanged(accuracy);
}
@Override
public void onSensorChanged(SensorEvent event) {
SensorData data = new SensorData();
data.accuracy = event.accuracy;
data.timeStamp = event.timestamp;
data.values = event.values;
mListener.onSensorChanged(data);
}
}
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package org.chromium.mojo.sensors;
import android.content.Context;
import org.chromium.mojo.system.MojoException;
import org.chromium.mojom.sensors.SensorListener;
import org.chromium.mojom.sensors.SensorService;
/**
* Android implementation of Senors.
*/
public class SensorServiceImpl implements SensorService {
private Context mContext;
public SensorServiceImpl(Context context) {
mContext = context;
}
@Override
public void close() {}
@Override
public void onConnectionError(MojoException e) {}
@Override
public void addListener(int sensorType, SensorListener listener) {
new SensorForwarder(mContext, sensorType, (SensorListener.Proxy) listener);
}
}
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package org.chromium.mojo.sensors;
import android.content.Context;
import org.chromium.mojo.application.ApplicationConnection;
import org.chromium.mojo.application.ApplicationDelegate;
import org.chromium.mojo.application.ApplicationRunner;
import org.chromium.mojo.application.ServiceFactoryBinder;
import org.chromium.mojo.bindings.InterfaceRequest;
import org.chromium.mojo.system.Core;
import org.chromium.mojo.system.MessagePipeHandle;
import org.chromium.mojom.mojo.Shell;
import org.chromium.mojom.sensors.SensorService;
/**
* Android service application implementing the SensorService interface.
*/
public class Sensors implements ApplicationDelegate {
private Context mContext;
public Sensors(Context context) {
mContext = context;
}
/**
* @see ApplicationDelegate#initialize(Shell, String[], String)
*/
@Override
public void initialize(Shell shell, String[] args, String url) {}
/**
* @see ApplicationDelegate#configureIncomingConnection(ApplicationConnection)
*/
@Override
public boolean configureIncomingConnection(ApplicationConnection connection) {
connection.addService(new ServiceFactoryBinder<SensorService>() {
@Override
public void bind(InterfaceRequest<SensorService> request) {
SensorService.MANAGER.bind(new SensorServiceImpl(mContext), request);
}
@Override
public String getInterfaceName() {
return SensorService.MANAGER.getName();
}
});
return true;
}
/**
* @see ApplicationDelegate#quit()
*/
@Override
public void quit() {}
public static void mojoMain(
Context context, Core core, MessagePipeHandle applicationRequestHandle) {
ApplicationRunner.run(new Sensors(context), core, applicationRequestHandle);
}
}
......@@ -86,19 +86,14 @@ android_library("java") {
"//flutter/services/editing:editing_lib",
"//flutter/services/editing:interfaces_java",
"//flutter/services/engine:interfaces_java",
"//flutter/services/media:interfaces_java",
"//flutter/services/media:media_lib",
"//flutter/services/platform:interfaces_java",
"//flutter/services/platform:platform_lib",
"//flutter/services/raw_keyboard:interfaces_java",
"//flutter/services/raw_keyboard:raw_keyboard_lib",
"//flutter/services/sensors:sensors_lib",
"//flutter/services/vsync:vsync_lib",
"//mojo/android:system_java",
"//mojo/public/interfaces/application:application_java",
"//mojo/public/java:bindings",
"//mojo/public/java:system",
"//mojo/services/sensors/interfaces:interfaces_java",
"//mojo/services/vsync/interfaces:interfaces_java",
]
}
......
......@@ -31,28 +31,14 @@ import org.chromium.base.library_loader.LibraryLoader;
import org.chromium.base.library_loader.LibraryProcessType;
import org.chromium.base.library_loader.ProcessInitException;
import org.chromium.mojo.bindings.Interface.Binding;
import org.chromium.mojo.sensors.SensorServiceImpl;
import org.chromium.mojo.system.Core;
import org.chromium.mojo.system.impl.CoreImpl;
import org.chromium.mojo.system.MessagePipeHandle;
import org.chromium.mojom.activity.Activity;
import org.chromium.mojom.editing.Clipboard;
import org.chromium.mojom.flutter.platform.HapticFeedback;
import org.chromium.mojom.flutter.platform.PathProvider;
import org.chromium.mojom.flutter.platform.SystemChrome;
import org.chromium.mojom.flutter.platform.SystemSound;
import org.chromium.mojom.flutter.platform.UrlLauncher;
import org.chromium.mojom.media.MediaService;
import org.chromium.mojom.sensors.SensorService;
import org.chromium.mojom.vsync.VSyncProvider;
import org.domokit.activity.ActivityImpl;
import org.domokit.editing.ClipboardImpl;
import org.domokit.media.MediaServiceImpl;
import org.domokit.platform.HapticFeedbackImpl;
import org.domokit.platform.PathProviderImpl;
import org.domokit.platform.SystemChromeImpl;
import org.domokit.platform.SystemSoundImpl;
import org.domokit.platform.UrlLauncherImpl;
import org.domokit.vsync.VSyncProviderImpl;
/**
......@@ -212,63 +198,12 @@ public class FlutterMain {
}
});
registry.register(MediaService.MANAGER.getName(), new ServiceFactory() {
@Override
public Binding connectToService(FlutterView view, Core core, MessagePipeHandle pipe) {
return MediaService.MANAGER.bind(new MediaServiceImpl(view.getContext(), core), pipe);
}
});
registry.register(SensorService.MANAGER.getName(), new ServiceFactory() {
@Override
public Binding connectToService(FlutterView view, Core core, MessagePipeHandle pipe) {
return SensorService.MANAGER.bind(new SensorServiceImpl(view.getContext()), pipe);
}
});
registry.register(VSyncProvider.MANAGER.getName(), new ServiceFactory() {
@Override
public Binding connectToService(FlutterView view, Core core, MessagePipeHandle pipe) {
return VSyncProvider.MANAGER.bind(new VSyncProviderImpl(pipe), pipe);
}
});
registry.register(HapticFeedback.MANAGER.getName(), new ServiceFactory() {
@Override
public Binding connectToService(FlutterView view, Core core, MessagePipeHandle pipe) {
return HapticFeedback.MANAGER.bind(new HapticFeedbackImpl((android.app.Activity) view.getContext()), pipe);
}
});
registry.register(PathProvider.MANAGER.getName(), new ServiceFactory() {
@Override
public Binding connectToService(FlutterView view, Core core, MessagePipeHandle pipe) {
return PathProvider.MANAGER.bind(new PathProviderImpl(view.getContext()), pipe);
}
});
registry.register(SystemChrome.MANAGER.getName(), new ServiceFactory() {
@Override
public Binding connectToService(FlutterView view, Core core, MessagePipeHandle pipe) {
SystemChromeImpl chrome = new SystemChromeImpl((android.app.Activity) view.getContext());
view.addActivityLifecycleListener(chrome);
return SystemChrome.MANAGER.bind(chrome, pipe);
}
});
registry.register(SystemSound.MANAGER.getName(), new ServiceFactory() {
@Override
public Binding connectToService(FlutterView view, Core core, MessagePipeHandle pipe) {
return SystemSound.MANAGER.bind(new SystemSoundImpl((android.app.Activity) view.getContext()), pipe);
}
});
registry.register(UrlLauncher.MANAGER.getName(), new ServiceFactory() {
@Override
public Binding connectToService(FlutterView view, Core core, MessagePipeHandle pipe) {
return UrlLauncher.MANAGER.bind(new UrlLauncherImpl((android.app.Activity) view.getContext()), pipe);
}
});
}
/**
......
......@@ -24,7 +24,6 @@ source_set("common") {
"//flutter/services/activity",
"//flutter/services/editing",
"//flutter/services/engine:interfaces",
"//flutter/services/media",
"//flutter/services/platform",
"//flutter/services/vsync",
"//flutter/shell/common",
......
......@@ -7,13 +7,6 @@
#if TARGET_OS_IPHONE
#include "flutter/services/activity/ios/activity_impl.h"
#include "flutter/services/editing/ios/clipboard_impl.h"
#include "flutter/services/media/ios/media_player_impl.h"
#include "flutter/services/media/ios/media_service_impl.h"
#include "flutter/services/platform/ios/haptic_feedback_impl.h"
#include "flutter/services/platform/ios/path_provider_impl.h"
#include "flutter/services/platform/ios/system_chrome_impl.h"
#include "flutter/services/platform/ios/system_sound_impl.h"
#include "flutter/services/platform/ios/url_launcher_impl.h"
#include "flutter/services/vsync/ios/vsync_provider_ios_impl.h"
#else
#include "flutter/services/vsync/mac/vsync_provider_mac_impl.h"
......@@ -31,16 +24,6 @@ void PlatformServiceProvider::ConnectToService(
const mojo::String& service_name,
mojo::ScopedMessagePipeHandle client_handle) {
#if TARGET_OS_IPHONE
if (service_name == ::media::MediaPlayer::Name_) {
new sky::services::media::MediaPlayerImpl(
mojo::InterfaceRequest<::media::MediaPlayer>(client_handle.Pass()));
return;
}
if (service_name == ::media::MediaService::Name_) {
new sky::services::media::MediaServiceImpl(
mojo::InterfaceRequest<::media::MediaService>(client_handle.Pass()));
return;
}
if (service_name == ::activity::Activity::Name_) {
new sky::services::activity::ActivityImpl(
mojo::InterfaceRequest<::activity::Activity>(client_handle.Pass()));
......@@ -51,36 +34,6 @@ void PlatformServiceProvider::ConnectToService(
mojo::InterfaceRequest<::editing::Clipboard>(client_handle.Pass()));
return;
}
if (service_name == flutter::platform::HapticFeedback::Name_) {
new flutter::platform::HapticFeedbackImpl(
mojo::InterfaceRequest<flutter::platform::HapticFeedback>(
client_handle.Pass()));
return;
}
if (service_name == flutter::platform::PathProvider::Name_) {
new flutter::platform::PathProviderImpl(
mojo::InterfaceRequest<flutter::platform::PathProvider>(
client_handle.Pass()));
return;
}
if (service_name == flutter::platform::SystemChrome::Name_) {
new flutter::platform::SystemChromeImpl(
mojo::InterfaceRequest<flutter::platform::SystemChrome>(
client_handle.Pass()));
return;
}
if (service_name == flutter::platform::SystemSound::Name_) {
new flutter::platform::SystemSoundImpl(
mojo::InterfaceRequest<flutter::platform::SystemSound>(
client_handle.Pass()));
return;
}
if (service_name == flutter::platform::URLLauncher::Name_) {
new flutter::platform::URLLauncherImpl(
mojo::InterfaceRequest<flutter::platform::URLLauncher>(
client_handle.Pass()));
return;
}
if (service_name == ::vsync::VSyncProvider::Name_) {
new sky::services::vsync::VsyncProviderIOSImpl(
mojo::InterfaceRequest<::vsync::VSyncProvider>(client_handle.Pass()));
......
......@@ -52,7 +52,6 @@ shared_library("flutter_framework_dylib") {
"//flutter/services/activity",
"//flutter/services/editing",
"//flutter/services/engine:interfaces",
"//flutter/services/media",
"//flutter/services/platform",
"//flutter/services/vsync",
"//flutter/shell/common",
......
......@@ -2,8 +2,22 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef SHELL_PLATFORM_IOS_FRAMEWORK_SOURCE_FLUTTERPLATFORM_PLUGIN_H_
#define SHELL_PLATFORM_IOS_FRAMEWORK_SOURCE_FLUTTERPLATFORM_PLUGIN_H_
#include "flutter/shell/platform/darwin/ios/framework/Headers/FlutterJSONMessageListener.h"
@interface FlutterPlatformPlugin : FlutterJSONMessageListener
@end
namespace shell {
extern const char* const kOrientationUpdateNotificationName;
extern const char* const kOrientationUpdateNotificationKey;
extern const char* const kOverlayStyleUpdateNotificationName;
extern const char* const kOverlayStyleUpdateNotificationKey;
} // namespace shell
#endif // SHELL_PLATFORM_IOS_FRAMEWORK_SOURCE_FLUTTERPLATFORM_PLUGIN_H_
......@@ -17,19 +17,21 @@ static NSDictionary* GetDirectoryOfType(NSSearchPathDirectory dir) {
return @{ @"path": paths.firstObject };
}
namespace flutter {
namespace platform {
namespace shell {
// TODO(abarth): Move these definitions from system_chrome_impl.cc to here.
extern const char* const kOrientationUpdateNotificationName;
extern const char* const kOrientationUpdateNotificationKey;
extern const char* const kOverlayStyleUpdateNotificationName;
extern const char* const kOverlayStyleUpdateNotificationKey;
} // namespace platform
} // namespace flutter
using namespace flutter::platform;
const char* const kOrientationUpdateNotificationName =
"io.flutter.plugin.platform.SystemChromeOrientationNotificationName";
const char* const kOrientationUpdateNotificationKey =
"io.flutter.plugin.platform.SystemChromeOrientationNotificationKey";
const char* const kOverlayStyleUpdateNotificationName =
"io.flutter.plugin.platform.SystemChromeOverlayNotificationName";
const char* const kOverlayStyleUpdateNotificationKey =
"io.flutter.plugin.platform.SystemChromeOverlayNotificationKey";
} // namespace shell
using namespace shell;
@implementation FlutterPlatformPlugin
......
......@@ -10,13 +10,12 @@
#include "base/mac/scoped_nsobject.h"
#include "base/strings/sys_string_conversions.h"
#include "flutter/common/threads.h"
#include "flutter/services/platform/ios/system_chrome_impl.h"
#include "flutter/shell/gpu/gpu_rasterizer.h"
#include "flutter/shell/gpu/gpu_surface_gl.h"
#include "flutter/shell/platform/darwin/common/platform_mac.h"
#include "flutter/shell/platform/darwin/ios/framework/Source/flutter_touch_mapper.h"
#include "flutter/shell/platform/darwin/ios/framework/Source/FlutterDartProject_Internal.h"
#include "flutter/shell/platform/darwin/ios/framework/Source/FlutterPlatformPlugin.h"
#include "flutter/shell/platform/darwin/ios/framework/Source/flutter_touch_mapper.h"
#include "flutter/shell/platform/darwin/ios/platform_view_ios.h"
#include "lib/ftl/functional/make_copyable.h"
#include "lib/ftl/time/time_delta.h"
......@@ -97,12 +96,12 @@ void FlutterInit(int argc, const char* argv[]) {
NSNotificationCenter* center = [NSNotificationCenter defaultCenter];
[center addObserver:self
selector:@selector(onOrientationPreferencesUpdated:)
name:@(flutter::platform::kOrientationUpdateNotificationName)
name:@(shell::kOrientationUpdateNotificationName)
object:nil];
[center addObserver:self
selector:@selector(onPreferredStatusBarStyleUpdated:)
name:@(flutter::platform::kOverlayStyleUpdateNotificationName)
name:@(shell::kOverlayStyleUpdateNotificationName)
object:nil];
[center addObserver:self
......@@ -339,7 +338,7 @@ static inline PointerChangeMapperPhase PointerChangePhaseFromUITouchPhase(
NSDictionary* info = notification.userInfo;
NSNumber* update =
info[@(flutter::platform::kOrientationUpdateNotificationKey)];
info[@(shell::kOrientationUpdateNotificationKey)];
if (update == nil) {
return;
......@@ -430,7 +429,7 @@ static inline PointerChangeMapperPhase PointerChangePhaseFromUITouchPhase(
NSDictionary* info = notification.userInfo;
NSNumber* update =
info[@(flutter::platform::kOverlayStyleUpdateNotificationKey)];
info[@(shell::kOverlayStyleUpdateNotificationKey)];
if (update == nil) {
return;
......
/// Copyright 2016 The Chromium Authors. All rights reserved.
/// Use of this source code is governed by a BSD-style license that can be
/// found in the LICENSE file.
import 'package:sky_services/media/media.mojom.dart';
export 'package:sky_services/media/media.mojom.dart';
/// Copyright 2016 The Chromium Authors. All rights reserved.
/// Use of this source code is governed by a BSD-style license that can be
/// found in the LICENSE file.
import 'package:mojo_services/mojo/geometry.mojom.dart';
export 'package:mojo_services/mojo/geometry.mojom.dart';
/// Copyright 2016 The Chromium Authors. All rights reserved.
/// Use of this source code is governed by a BSD-style license that can be
/// found in the LICENSE file.
import 'package:mojo_services/mojo/network_service.mojom.dart';
export 'package:mojo_services/mojo/network_service.mojom.dart';
/// Copyright 2016 The Chromium Authors. All rights reserved.
/// Use of this source code is governed by a BSD-style license that can be
/// found in the LICENSE file.
import 'package:mojo_services/mojo/url_loader.mojom.dart';
export 'package:mojo_services/mojo/url_loader.mojom.dart';
/// Copyright 2016 The Chromium Authors. All rights reserved.
/// Use of this source code is governed by a BSD-style license that can be
/// found in the LICENSE file.
import 'package:sky_services/flutter/platform/haptic_feedback.mojom.dart';
export 'package:sky_services/flutter/platform/haptic_feedback.mojom.dart';
/// Copyright 2016 The Chromium Authors. All rights reserved.
/// Use of this source code is governed by a BSD-style license that can be
/// found in the LICENSE file.
import 'package:sky_services/flutter/platform/path_provider.mojom.dart';
export 'package:sky_services/flutter/platform/path_provider.mojom.dart';
/// Copyright 2016 The Chromium Authors. All rights reserved.
/// Use of this source code is governed by a BSD-style license that can be
/// found in the LICENSE file.
import 'package:sky_services/flutter/platform/system_chrome.mojom.dart';
export 'package:sky_services/flutter/platform/system_chrome.mojom.dart';
/// Copyright 2016 The Chromium Authors. All rights reserved.
/// Use of this source code is governed by a BSD-style license that can be
/// found in the LICENSE file.
import 'package:sky_services/flutter/platform/system_sound.mojom.dart';
export 'package:sky_services/flutter/platform/system_sound.mojom.dart';
/// Copyright 2016 The Chromium Authors. All rights reserved.
/// Use of this source code is governed by a BSD-style license that can be
/// found in the LICENSE file.
import 'package:sky_services/flutter/platform/url_launcher.mojom.dart';
export 'package:sky_services/flutter/platform/url_launcher.mojom.dart';
......@@ -25,7 +25,6 @@ dart_pkg("sky_services") {
":copy_sky_services_license",
"//flutter/services/activity:interfaces",
"//flutter/services/editing:interfaces",
"//flutter/services/media:interfaces",
"//flutter/services/platform:interfaces",
"//flutter/services/raw_keyboard:interfaces",
]
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册