зеркало из https://github.com/mozilla/pjs.git
Merge mozilla-central and mozilla-inbound
This commit is contained in:
Коммит
e19ebcf168
|
@ -691,6 +691,7 @@ ANDROID_PLATFORM = @ANDROID_PLATFORM@
|
|||
ANDROID_SDK = @ANDROID_SDK@
|
||||
ANDROID_PLATFORM_TOOLS = @ANDROID_PLATFORM_TOOLS@
|
||||
ANDROID_VERSION = @ANDROID_VERSION@
|
||||
ANDROID_SOURCE = @ANDROID_SOURCE@
|
||||
STLPORT_SOURCES = @STLPORT_SOURCES@
|
||||
|
||||
ANDROID_PACKAGE_NAME = @ANDROID_PACKAGE_NAME@
|
||||
|
|
24
configure.in
24
configure.in
|
@ -301,19 +301,25 @@ MOZ_ARG_WITH_STRING(gonk,
|
|||
location of gonk dir],
|
||||
gonkdir=$withval)
|
||||
|
||||
MOZ_ARG_WITH_STRING(gonk-toolchain-prefix,
|
||||
[ --with-gonk-toolchain-prefix=DIR
|
||||
prefix to gonk toolchain commands],
|
||||
gonk_toolchain_prefix=$withval)
|
||||
|
||||
if test -n "$gonkdir" ; then
|
||||
kernel_name=`uname -s | tr "[[:upper:]]" "[[:lower:]]"`
|
||||
gonk_toolchain="$gonkdir"/prebuilt/$kernel_name-x86/toolchain/arm-eabi-4.4.3
|
||||
android_source="$gonkdir"
|
||||
ANDROID_SOURCE="$android_source"
|
||||
|
||||
dnl set up compilers
|
||||
AS="$gonk_toolchain"/bin/"$android_tool_prefix"-as
|
||||
CC="$gonk_toolchain"/bin/"$android_tool_prefix"-gcc
|
||||
CXX="$gonk_toolchain"/bin/"$android_tool_prefix"-g++
|
||||
CPP="$gonk_toolchain"/bin/"$android_tool_prefix"-cpp
|
||||
LD="$gonk_toolchain"/bin/"$android_tool_prefix"-ld
|
||||
AR="$gonk_toolchain"/bin/"$android_tool_prefix"-ar
|
||||
RANLIB="$gonk_toolchain"/bin/"$android_tool_prefix"-ranlib
|
||||
STRIP="$gonk_toolchain"/bin/"$android_tool_prefix"-strip
|
||||
AS="$gonk_toolchain_prefix"as
|
||||
CC="$gonk_toolchain_prefix"gcc
|
||||
CXX="$gonk_toolchain_prefix"g++
|
||||
CPP="$gonk_toolchain_prefix"cpp
|
||||
LD="$gonk_toolchain_prefix"ld
|
||||
AR="$gonk_toolchain_prefix"ar
|
||||
RANLIB="$gonk_toolchain_prefix"ranlib
|
||||
STRIP="$gonk_toolchain_prefix"strip
|
||||
|
||||
STLPORT_CPPFLAGS="-I$gonkdir/ndk/sources/cxx-stl/stlport/stlport/"
|
||||
STLPORT_LIBS="-lstlport"
|
||||
|
|
|
@ -90,6 +90,10 @@ PowerManager::Shutdown()
|
|||
nsresult
|
||||
PowerManager::CheckPermission()
|
||||
{
|
||||
if (nsContentUtils::IsCallerChrome()) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsPIDOMWindow> win = do_QueryReferent(mWindow);
|
||||
NS_ENSURE_STATE(win);
|
||||
nsCOMPtr<nsIDocument> doc = do_QueryInterface(win->GetExtantDocument());
|
||||
|
|
|
@ -36,7 +36,7 @@
|
|||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#include "AudioManager.h"
|
||||
#include <media/AudioSystem.h>
|
||||
#include "gonk/AudioSystem.h"
|
||||
|
||||
using namespace mozilla::dom::gonk;
|
||||
using namespace android;
|
||||
|
@ -120,15 +120,21 @@ AudioManager::SetPhoneState(PRInt32 aState)
|
|||
NS_IMETHODIMP
|
||||
AudioManager::SetForceForUse(PRInt32 aUsage, PRInt32 aForce)
|
||||
{
|
||||
/*
|
||||
* FIXME/bug XXXXXX: why do we need to disable forceUse in ICS?
|
||||
if (AudioSystem::setForceUse((AudioSystem::force_use)aUsage,
|
||||
(AudioSystem::forced_config)aForce)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
*/
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
AudioManager::GetForceForUse(PRInt32 aUsage, PRInt32* aForce) {
|
||||
/*
|
||||
* FIXME/bug XXXXXX: why do we need to disable forceUse in ICS?
|
||||
*aForce = AudioSystem::getForceUse((AudioSystem::force_use)aUsage);
|
||||
*/
|
||||
return NS_OK;
|
||||
}
|
||||
|
|
|
@ -23,13 +23,6 @@ CPPSRCS = \
|
|||
SystemWorkerManager.cpp \
|
||||
$(NULL)
|
||||
|
||||
ifeq (gonk,$(MOZ_WIDGET_TOOLKIT))
|
||||
CPPSRCS += \
|
||||
AudioManager.cpp \
|
||||
GonkGPSGeolocationProvider.cpp \
|
||||
$(NULL)
|
||||
endif
|
||||
|
||||
XPIDLSRCS = \
|
||||
nsIAudioManager.idl \
|
||||
nsIRadioInterfaceLayer.idl \
|
||||
|
@ -44,6 +37,15 @@ LOCAL_INCLUDES = \
|
|||
-I$(topsrcdir)/content/events/src \
|
||||
$(NULL)
|
||||
|
||||
ifeq (gonk,$(MOZ_WIDGET_TOOLKIT))
|
||||
CPPSRCS += \
|
||||
AudioManager.cpp \
|
||||
GonkGPSGeolocationProvider.cpp \
|
||||
$(NULL)
|
||||
# for our local copy of AudioSystem.h
|
||||
LOCAL_INCLUDES += -I$(topsrcdir)/media/libsydneyaudio/src
|
||||
endif
|
||||
|
||||
EXTRA_COMPONENTS = \
|
||||
RadioInterfaceLayer.manifest \
|
||||
RadioInterfaceLayer.js \
|
||||
|
|
|
@ -292,19 +292,23 @@ MOZ_ARG_WITH_STRING(gonk,
|
|||
location of gonk dir],
|
||||
gonkdir=$withval)
|
||||
|
||||
MOZ_ARG_WITH_STRING(gonk-toolchain-prefix,
|
||||
[ --with-gonk-toolchain-prefix=DIR
|
||||
prefix to gonk toolchain commands],
|
||||
gonk_toolchain_prefix=$withval)
|
||||
|
||||
if test -n "$gonkdir" ; then
|
||||
kernel_name=`uname -s | tr "[[:upper:]]" "[[:lower:]]"`
|
||||
gonk_toolchain="$gonkdir"/prebuilt/$kernel_name-x86/toolchain/arm-eabi-4.4.3
|
||||
|
||||
dnl set up compilers
|
||||
AS="$gonk_toolchain"/bin/"$android_tool_prefix"-as
|
||||
CC="$gonk_toolchain"/bin/"$android_tool_prefix"-gcc
|
||||
CXX="$gonk_toolchain"/bin/"$android_tool_prefix"-g++
|
||||
CPP="$gonk_toolchain"/bin/"$android_tool_prefix"-cpp
|
||||
LD="$gonk_toolchain"/bin/"$android_tool_prefix"-ld
|
||||
AR="$gonk_toolchain"/bin/"$android_tool_prefix"-ar
|
||||
RANLIB="$gonk_toolchain"/bin/"$android_tool_prefix"-ranlib
|
||||
STRIP="$gonk_toolchain"/bin/"$android_tool_prefix"-strip
|
||||
AS="$gonk_toolchain_prefix"as
|
||||
CC="$gonk_toolchain_prefix"gcc
|
||||
CXX="$gonk_toolchain_prefix"g++
|
||||
CPP="$gonk_toolchain_prefix"cpp
|
||||
LD="$gonk_toolchain_prefix"ld
|
||||
AR="$gonk_toolchain_prefix"ar
|
||||
RANLIB="$gonk_toolchain_prefix"ranlib
|
||||
STRIP="$gonk_toolchain_prefix"strip
|
||||
|
||||
STLPORT_CPPFLAGS="-I$gonkdir/external/stlport/stlport"
|
||||
STLPORT_LIBS="-lstlport"
|
||||
|
|
|
@ -0,0 +1,514 @@
|
|||
/*
|
||||
* Copyright (C) 2008 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef ANDROID_AUDIOSYSTEM_H_
|
||||
#define ANDROID_AUDIOSYSTEM_H_
|
||||
|
||||
#include <utils/RefBase.h>
|
||||
#include <utils/threads.h>
|
||||
#include "IAudioFlinger.h"
|
||||
|
||||
namespace android {
|
||||
|
||||
typedef void (*audio_error_callback)(status_t err);
|
||||
typedef int audio_io_handle_t;
|
||||
|
||||
class IAudioPolicyService;
|
||||
class String8;
|
||||
|
||||
class AudioSystem
|
||||
{
|
||||
public:
|
||||
|
||||
enum stream_type {
|
||||
DEFAULT =-1,
|
||||
VOICE_CALL = 0,
|
||||
SYSTEM = 1,
|
||||
RING = 2,
|
||||
MUSIC = 3,
|
||||
ALARM = 4,
|
||||
NOTIFICATION = 5,
|
||||
BLUETOOTH_SCO = 6,
|
||||
ENFORCED_AUDIBLE = 7, // Sounds that cannot be muted by user and must be routed to speaker
|
||||
DTMF = 8,
|
||||
TTS = 9,
|
||||
NUM_STREAM_TYPES
|
||||
};
|
||||
|
||||
// Audio sub formats (see AudioSystem::audio_format).
|
||||
enum pcm_sub_format {
|
||||
PCM_SUB_16_BIT = 0x1, // must be 1 for backward compatibility
|
||||
PCM_SUB_8_BIT = 0x2, // must be 2 for backward compatibility
|
||||
};
|
||||
|
||||
// MP3 sub format field definition : can use 11 LSBs in the same way as MP3 frame header to specify
|
||||
// bit rate, stereo mode, version...
|
||||
enum mp3_sub_format {
|
||||
//TODO
|
||||
};
|
||||
|
||||
// AMR NB/WB sub format field definition: specify frame block interleaving, bandwidth efficient or octet aligned,
|
||||
// encoding mode for recording...
|
||||
enum amr_sub_format {
|
||||
//TODO
|
||||
};
|
||||
|
||||
// AAC sub format field definition: specify profile or bitrate for recording...
|
||||
enum aac_sub_format {
|
||||
//TODO
|
||||
};
|
||||
|
||||
// VORBIS sub format field definition: specify quality for recording...
|
||||
enum vorbis_sub_format {
|
||||
//TODO
|
||||
};
|
||||
|
||||
// Audio format consists in a main format field (upper 8 bits) and a sub format field (lower 24 bits).
|
||||
// The main format indicates the main codec type. The sub format field indicates options and parameters
|
||||
// for each format. The sub format is mainly used for record to indicate for instance the requested bitrate
|
||||
// or profile. It can also be used for certain formats to give informations not present in the encoded
|
||||
// audio stream (e.g. octet alignement for AMR).
|
||||
enum audio_format {
|
||||
INVALID_FORMAT = -1,
|
||||
FORMAT_DEFAULT = 0,
|
||||
PCM = 0x00000000, // must be 0 for backward compatibility
|
||||
MP3 = 0x01000000,
|
||||
AMR_NB = 0x02000000,
|
||||
AMR_WB = 0x03000000,
|
||||
AAC = 0x04000000,
|
||||
HE_AAC_V1 = 0x05000000,
|
||||
HE_AAC_V2 = 0x06000000,
|
||||
VORBIS = 0x07000000,
|
||||
EVRC = 0x08000000,
|
||||
QCELP = 0x09000000,
|
||||
VOIP_PCM_INPUT = 0x0A000000,
|
||||
MAIN_FORMAT_MASK = 0xFF000000,
|
||||
SUB_FORMAT_MASK = 0x00FFFFFF,
|
||||
// Aliases
|
||||
PCM_16_BIT = (PCM|PCM_SUB_16_BIT),
|
||||
PCM_8_BIT = (PCM|PCM_SUB_8_BIT)
|
||||
};
|
||||
|
||||
|
||||
// Channel mask definitions must be kept in sync with JAVA values in /media/java/android/media/AudioFormat.java
|
||||
enum audio_channels {
|
||||
// output channels
|
||||
CHANNEL_OUT_FRONT_LEFT = 0x4,
|
||||
CHANNEL_OUT_FRONT_RIGHT = 0x8,
|
||||
CHANNEL_OUT_FRONT_CENTER = 0x10,
|
||||
CHANNEL_OUT_LOW_FREQUENCY = 0x20,
|
||||
CHANNEL_OUT_BACK_LEFT = 0x40,
|
||||
CHANNEL_OUT_BACK_RIGHT = 0x80,
|
||||
CHANNEL_OUT_FRONT_LEFT_OF_CENTER = 0x100,
|
||||
CHANNEL_OUT_FRONT_RIGHT_OF_CENTER = 0x200,
|
||||
CHANNEL_OUT_BACK_CENTER = 0x400,
|
||||
CHANNEL_OUT_MONO = CHANNEL_OUT_FRONT_LEFT,
|
||||
CHANNEL_OUT_STEREO = (CHANNEL_OUT_FRONT_LEFT | CHANNEL_OUT_FRONT_RIGHT),
|
||||
CHANNEL_OUT_QUAD = (CHANNEL_OUT_FRONT_LEFT | CHANNEL_OUT_FRONT_RIGHT |
|
||||
CHANNEL_OUT_BACK_LEFT | CHANNEL_OUT_BACK_RIGHT),
|
||||
CHANNEL_OUT_SURROUND = (CHANNEL_OUT_FRONT_LEFT | CHANNEL_OUT_FRONT_RIGHT |
|
||||
CHANNEL_OUT_FRONT_CENTER | CHANNEL_OUT_BACK_CENTER),
|
||||
CHANNEL_OUT_5POINT1 = (CHANNEL_OUT_FRONT_LEFT | CHANNEL_OUT_FRONT_RIGHT |
|
||||
CHANNEL_OUT_FRONT_CENTER | CHANNEL_OUT_LOW_FREQUENCY | CHANNEL_OUT_BACK_LEFT | CHANNEL_OUT_BACK_RIGHT),
|
||||
CHANNEL_OUT_7POINT1 = (CHANNEL_OUT_FRONT_LEFT | CHANNEL_OUT_FRONT_RIGHT |
|
||||
CHANNEL_OUT_FRONT_CENTER | CHANNEL_OUT_LOW_FREQUENCY | CHANNEL_OUT_BACK_LEFT | CHANNEL_OUT_BACK_RIGHT |
|
||||
CHANNEL_OUT_FRONT_LEFT_OF_CENTER | CHANNEL_OUT_FRONT_RIGHT_OF_CENTER),
|
||||
CHANNEL_OUT_ALL = (CHANNEL_OUT_FRONT_LEFT | CHANNEL_OUT_FRONT_RIGHT |
|
||||
CHANNEL_OUT_FRONT_CENTER | CHANNEL_OUT_LOW_FREQUENCY | CHANNEL_OUT_BACK_LEFT | CHANNEL_OUT_BACK_RIGHT |
|
||||
CHANNEL_OUT_FRONT_LEFT_OF_CENTER | CHANNEL_OUT_FRONT_RIGHT_OF_CENTER | CHANNEL_OUT_BACK_CENTER),
|
||||
|
||||
// input channels
|
||||
CHANNEL_IN_LEFT = 0x4,
|
||||
CHANNEL_IN_RIGHT = 0x8,
|
||||
CHANNEL_IN_FRONT = 0x10,
|
||||
CHANNEL_IN_BACK = 0x20,
|
||||
CHANNEL_IN_LEFT_PROCESSED = 0x40,
|
||||
CHANNEL_IN_RIGHT_PROCESSED = 0x80,
|
||||
CHANNEL_IN_FRONT_PROCESSED = 0x100,
|
||||
CHANNEL_IN_BACK_PROCESSED = 0x200,
|
||||
CHANNEL_IN_PRESSURE = 0x400,
|
||||
CHANNEL_IN_X_AXIS = 0x800,
|
||||
CHANNEL_IN_Y_AXIS = 0x1000,
|
||||
CHANNEL_IN_Z_AXIS = 0x2000,
|
||||
CHANNEL_IN_VOICE_UPLINK = 0x4000,
|
||||
CHANNEL_IN_VOICE_DNLINK = 0x8000,
|
||||
CHANNEL_IN_MONO = CHANNEL_IN_FRONT,
|
||||
CHANNEL_IN_STEREO = (CHANNEL_IN_LEFT | CHANNEL_IN_RIGHT),
|
||||
CHANNEL_IN_ALL = (CHANNEL_IN_LEFT | CHANNEL_IN_RIGHT | CHANNEL_IN_FRONT | CHANNEL_IN_BACK|
|
||||
CHANNEL_IN_LEFT_PROCESSED | CHANNEL_IN_RIGHT_PROCESSED | CHANNEL_IN_FRONT_PROCESSED | CHANNEL_IN_BACK_PROCESSED|
|
||||
CHANNEL_IN_PRESSURE | CHANNEL_IN_X_AXIS | CHANNEL_IN_Y_AXIS | CHANNEL_IN_Z_AXIS |
|
||||
CHANNEL_IN_VOICE_UPLINK | CHANNEL_IN_VOICE_DNLINK)
|
||||
};
|
||||
|
||||
enum audio_mode {
|
||||
MODE_INVALID = -2,
|
||||
MODE_CURRENT = -1,
|
||||
MODE_NORMAL = 0,
|
||||
MODE_RINGTONE,
|
||||
MODE_IN_CALL,
|
||||
MODE_IN_COMMUNICATION,
|
||||
NUM_MODES // not a valid entry, denotes end-of-list
|
||||
};
|
||||
|
||||
enum audio_in_acoustics {
|
||||
AGC_ENABLE = 0x0001,
|
||||
AGC_DISABLE = 0,
|
||||
NS_ENABLE = 0x0002,
|
||||
NS_DISABLE = 0,
|
||||
TX_IIR_ENABLE = 0x0004,
|
||||
TX_DISABLE = 0
|
||||
};
|
||||
|
||||
// special audio session values
|
||||
enum audio_sessions {
|
||||
SESSION_OUTPUT_STAGE = -1, // session for effects attached to a particular output stream
|
||||
// (value must be less than 0)
|
||||
SESSION_OUTPUT_MIX = 0, // session for effects applied to output mix. These effects can
|
||||
// be moved by audio policy manager to another output stream
|
||||
// (value must be 0)
|
||||
};
|
||||
|
||||
/* These are static methods to control the system-wide AudioFlinger
|
||||
* only privileged processes can have access to them
|
||||
*/
|
||||
|
||||
// mute/unmute microphone
|
||||
static status_t muteMicrophone(bool state);
|
||||
static status_t isMicrophoneMuted(bool *state);
|
||||
|
||||
// set/get master volume
|
||||
static status_t setMasterVolume(float value);
|
||||
static status_t getMasterVolume(float* volume);
|
||||
// mute/unmute audio outputs
|
||||
static status_t setMasterMute(bool mute);
|
||||
static status_t getMasterMute(bool* mute);
|
||||
|
||||
// set/get stream volume on specified output
|
||||
static status_t setStreamVolume(int stream, float value, int output);
|
||||
static status_t getStreamVolume(int stream, float* volume, int output);
|
||||
|
||||
// mute/unmute stream
|
||||
static status_t setStreamMute(int stream, bool mute);
|
||||
static status_t getStreamMute(int stream, bool* mute);
|
||||
|
||||
// set audio mode in audio hardware (see AudioSystem::audio_mode)
|
||||
static status_t setMode(int mode);
|
||||
|
||||
// returns true in *state if tracks are active on the specified stream
|
||||
static status_t isStreamActive(int stream, bool *state);
|
||||
|
||||
// set/get audio hardware parameters. The function accepts a list of parameters
|
||||
// key value pairs in the form: key1=value1;key2=value2;...
|
||||
// Some keys are reserved for standard parameters (See AudioParameter class).
|
||||
static status_t setParameters(audio_io_handle_t ioHandle, const String8& keyValuePairs);
|
||||
static String8 getParameters(audio_io_handle_t ioHandle, const String8& keys);
|
||||
|
||||
static void setErrorCallback(audio_error_callback cb);
|
||||
|
||||
// helper function to obtain AudioFlinger service handle
|
||||
static const sp<IAudioFlinger>& get_audio_flinger();
|
||||
|
||||
static float linearToLog(int volume);
|
||||
static int logToLinear(float volume);
|
||||
|
||||
static status_t getOutputSamplingRate(int* samplingRate, int stream = DEFAULT);
|
||||
static status_t getOutputFrameCount(int* frameCount, int stream = DEFAULT);
|
||||
static status_t getOutputLatency(uint32_t* latency, int stream = DEFAULT);
|
||||
|
||||
static bool routedToA2dpOutput(int streamType);
|
||||
|
||||
static status_t getInputBufferSize(uint32_t sampleRate, int format, int channelCount,
|
||||
size_t* buffSize);
|
||||
|
||||
static status_t setVoiceVolume(float volume);
|
||||
|
||||
// return the number of audio frames written by AudioFlinger to audio HAL and
|
||||
// audio dsp to DAC since the output on which the specificed stream is playing
|
||||
// has exited standby.
|
||||
// returned status (from utils/Errors.h) can be:
|
||||
// - NO_ERROR: successful operation, halFrames and dspFrames point to valid data
|
||||
// - INVALID_OPERATION: Not supported on current hardware platform
|
||||
// - BAD_VALUE: invalid parameter
|
||||
// NOTE: this feature is not supported on all hardware platforms and it is
|
||||
// necessary to check returned status before using the returned values.
|
||||
static status_t getRenderPosition(uint32_t *halFrames, uint32_t *dspFrames, int stream = DEFAULT);
|
||||
|
||||
static unsigned int getInputFramesLost(audio_io_handle_t ioHandle);
|
||||
|
||||
static int newAudioSessionId();
|
||||
//
|
||||
// AudioPolicyService interface
|
||||
//
|
||||
|
||||
enum audio_devices {
|
||||
// output devices
|
||||
DEVICE_OUT_EARPIECE = 0x1,
|
||||
DEVICE_OUT_SPEAKER = 0x2,
|
||||
DEVICE_OUT_WIRED_HEADSET = 0x4,
|
||||
DEVICE_OUT_WIRED_HEADPHONE = 0x8,
|
||||
DEVICE_OUT_BLUETOOTH_SCO = 0x10,
|
||||
DEVICE_OUT_BLUETOOTH_SCO_HEADSET = 0x20,
|
||||
DEVICE_OUT_BLUETOOTH_SCO_CARKIT = 0x40,
|
||||
DEVICE_OUT_BLUETOOTH_A2DP = 0x80,
|
||||
DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES = 0x100,
|
||||
DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER = 0x200,
|
||||
DEVICE_OUT_AUX_DIGITAL = 0x400,
|
||||
DEVICE_OUT_DEFAULT = 0x8000,
|
||||
DEVICE_OUT_ALL = (DEVICE_OUT_EARPIECE | DEVICE_OUT_SPEAKER | DEVICE_OUT_WIRED_HEADSET |
|
||||
DEVICE_OUT_WIRED_HEADPHONE | DEVICE_OUT_BLUETOOTH_SCO | DEVICE_OUT_BLUETOOTH_SCO_HEADSET |
|
||||
DEVICE_OUT_BLUETOOTH_SCO_CARKIT | DEVICE_OUT_BLUETOOTH_A2DP | DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES |
|
||||
DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER | DEVICE_OUT_AUX_DIGITAL | DEVICE_OUT_DEFAULT),
|
||||
DEVICE_OUT_ALL_A2DP = (DEVICE_OUT_BLUETOOTH_A2DP | DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES |
|
||||
DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER),
|
||||
|
||||
// input devices
|
||||
DEVICE_IN_COMMUNICATION = 0x10000,
|
||||
DEVICE_IN_AMBIENT = 0x20000,
|
||||
DEVICE_IN_BUILTIN_MIC = 0x40000,
|
||||
DEVICE_IN_BLUETOOTH_SCO_HEADSET = 0x80000,
|
||||
DEVICE_IN_WIRED_HEADSET = 0x100000,
|
||||
DEVICE_IN_AUX_DIGITAL = 0x200000,
|
||||
DEVICE_IN_VOICE_CALL = 0x400000,
|
||||
DEVICE_IN_BACK_MIC = 0x800000,
|
||||
DEVICE_IN_DEFAULT = 0x80000000,
|
||||
|
||||
DEVICE_IN_ALL = (DEVICE_IN_COMMUNICATION | DEVICE_IN_AMBIENT | DEVICE_IN_BUILTIN_MIC |
|
||||
DEVICE_IN_BLUETOOTH_SCO_HEADSET | DEVICE_IN_WIRED_HEADSET | DEVICE_IN_AUX_DIGITAL |
|
||||
DEVICE_IN_VOICE_CALL | DEVICE_IN_BACK_MIC | DEVICE_IN_DEFAULT)
|
||||
};
|
||||
|
||||
// device connection states used for setDeviceConnectionState()
|
||||
enum device_connection_state {
|
||||
DEVICE_STATE_UNAVAILABLE,
|
||||
DEVICE_STATE_AVAILABLE,
|
||||
NUM_DEVICE_STATES
|
||||
};
|
||||
|
||||
// request to open a direct output with getOutput() (by opposition to sharing an output with other AudioTracks)
|
||||
enum output_flags {
|
||||
OUTPUT_FLAG_INDIRECT = 0x0,
|
||||
OUTPUT_FLAG_DIRECT = 0x1
|
||||
};
|
||||
|
||||
// device categories used for setForceUse()
|
||||
enum forced_config {
|
||||
FORCE_NONE,
|
||||
FORCE_SPEAKER,
|
||||
FORCE_HEADPHONES,
|
||||
FORCE_BT_SCO,
|
||||
FORCE_BT_A2DP,
|
||||
FORCE_WIRED_ACCESSORY,
|
||||
FORCE_BT_CAR_DOCK,
|
||||
FORCE_BT_DESK_DOCK,
|
||||
NUM_FORCE_CONFIG,
|
||||
FORCE_DEFAULT = FORCE_NONE
|
||||
};
|
||||
|
||||
// usages used for setForceUse()
|
||||
enum force_use {
|
||||
FOR_COMMUNICATION,
|
||||
FOR_MEDIA,
|
||||
FOR_RECORD,
|
||||
FOR_DOCK,
|
||||
NUM_FORCE_USE
|
||||
};
|
||||
|
||||
// types of io configuration change events received with ioConfigChanged()
|
||||
enum io_config_event {
|
||||
OUTPUT_OPENED,
|
||||
OUTPUT_CLOSED,
|
||||
OUTPUT_CONFIG_CHANGED,
|
||||
INPUT_OPENED,
|
||||
INPUT_CLOSED,
|
||||
INPUT_CONFIG_CHANGED,
|
||||
STREAM_CONFIG_CHANGED,
|
||||
NUM_CONFIG_EVENTS
|
||||
};
|
||||
|
||||
// audio output descritor used to cache output configurations in client process to avoid frequent calls
|
||||
// through IAudioFlinger
|
||||
class OutputDescriptor {
|
||||
public:
|
||||
OutputDescriptor()
|
||||
: samplingRate(0), format(0), channels(0), frameCount(0), latency(0) {}
|
||||
|
||||
uint32_t samplingRate;
|
||||
int32_t format;
|
||||
int32_t channels;
|
||||
size_t frameCount;
|
||||
uint32_t latency;
|
||||
};
|
||||
|
||||
//
|
||||
// IAudioPolicyService interface (see AudioPolicyInterface for method descriptions)
|
||||
//
|
||||
static status_t setDeviceConnectionState(audio_devices device, device_connection_state state, const char *device_address);
|
||||
static device_connection_state getDeviceConnectionState(audio_devices device, const char *device_address);
|
||||
static status_t setPhoneState(int state);
|
||||
static status_t setRingerMode(uint32_t mode, uint32_t mask);
|
||||
static status_t setForceUse(force_use usage, forced_config config);
|
||||
static forced_config getForceUse(force_use usage);
|
||||
static audio_io_handle_t getOutput(stream_type stream,
|
||||
uint32_t samplingRate = 0,
|
||||
uint32_t format = FORMAT_DEFAULT,
|
||||
uint32_t channels = CHANNEL_OUT_STEREO,
|
||||
output_flags flags = OUTPUT_FLAG_INDIRECT);
|
||||
static status_t startOutput(audio_io_handle_t output,
|
||||
AudioSystem::stream_type stream,
|
||||
int session = 0);
|
||||
static status_t stopOutput(audio_io_handle_t output,
|
||||
AudioSystem::stream_type stream,
|
||||
int session = 0);
|
||||
static void releaseOutput(audio_io_handle_t output);
|
||||
static audio_io_handle_t getInput(int inputSource,
|
||||
uint32_t samplingRate = 0,
|
||||
uint32_t format = FORMAT_DEFAULT,
|
||||
uint32_t channels = CHANNEL_IN_MONO,
|
||||
audio_in_acoustics acoustics = (audio_in_acoustics)0);
|
||||
static status_t startInput(audio_io_handle_t input);
|
||||
static status_t stopInput(audio_io_handle_t input);
|
||||
static void releaseInput(audio_io_handle_t input);
|
||||
static status_t initStreamVolume(stream_type stream,
|
||||
int indexMin,
|
||||
int indexMax);
|
||||
static status_t setStreamVolumeIndex(stream_type stream, int index);
|
||||
static status_t getStreamVolumeIndex(stream_type stream, int *index);
|
||||
|
||||
static uint32_t getStrategyForStream(stream_type stream);
|
||||
|
||||
static audio_io_handle_t getOutputForEffect(effect_descriptor_t *desc);
|
||||
static status_t registerEffect(effect_descriptor_t *desc,
|
||||
audio_io_handle_t output,
|
||||
uint32_t strategy,
|
||||
int session,
|
||||
int id);
|
||||
static status_t unregisterEffect(int id);
|
||||
|
||||
static const sp<IAudioPolicyService>& get_audio_policy_service();
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
static uint32_t popCount(uint32_t u);
|
||||
static bool isOutputDevice(audio_devices device);
|
||||
static bool isInputDevice(audio_devices device);
|
||||
static bool isA2dpDevice(audio_devices device);
|
||||
static bool isBluetoothScoDevice(audio_devices device);
|
||||
static bool isSeperatedStream(stream_type stream);
|
||||
static bool isLowVisibility(stream_type stream);
|
||||
static bool isOutputChannel(uint32_t channel);
|
||||
static bool isInputChannel(uint32_t channel);
|
||||
static bool isValidFormat(uint32_t format);
|
||||
static bool isLinearPCM(uint32_t format);
|
||||
static bool isModeInCall();
|
||||
|
||||
private:
|
||||
|
||||
class AudioFlingerClient: public IBinder::DeathRecipient, public BnAudioFlingerClient
|
||||
{
|
||||
public:
|
||||
AudioFlingerClient() {
|
||||
}
|
||||
|
||||
// DeathRecipient
|
||||
virtual void binderDied(const wp<IBinder>& who);
|
||||
|
||||
// IAudioFlingerClient
|
||||
|
||||
// indicate a change in the configuration of an output or input: keeps the cached
|
||||
// values for output/input parameters upto date in client process
|
||||
virtual void ioConfigChanged(int event, int ioHandle, void *param2);
|
||||
};
|
||||
|
||||
class AudioPolicyServiceClient: public IBinder::DeathRecipient
|
||||
{
|
||||
public:
|
||||
AudioPolicyServiceClient() {
|
||||
}
|
||||
|
||||
// DeathRecipient
|
||||
virtual void binderDied(const wp<IBinder>& who);
|
||||
};
|
||||
|
||||
static sp<AudioFlingerClient> gAudioFlingerClient;
|
||||
static sp<AudioPolicyServiceClient> gAudioPolicyServiceClient;
|
||||
friend class AudioFlingerClient;
|
||||
friend class AudioPolicyServiceClient;
|
||||
|
||||
static Mutex gLock;
|
||||
static sp<IAudioFlinger> gAudioFlinger;
|
||||
static audio_error_callback gAudioErrorCallback;
|
||||
|
||||
static size_t gInBuffSize;
|
||||
// previous parameters for recording buffer size queries
|
||||
static uint32_t gPrevInSamplingRate;
|
||||
static int gPrevInFormat;
|
||||
static int gPrevInChannelCount;
|
||||
|
||||
static sp<IAudioPolicyService> gAudioPolicyService;
|
||||
|
||||
// mapping between stream types and outputs
|
||||
static DefaultKeyedVector<int, audio_io_handle_t> gStreamOutputMap;
|
||||
// list of output descritor containing cached parameters (sampling rate, framecount, channel count...)
|
||||
static DefaultKeyedVector<audio_io_handle_t, OutputDescriptor *> gOutputs;
|
||||
};
|
||||
|
||||
class AudioParameter {
|
||||
|
||||
public:
|
||||
AudioParameter() {}
|
||||
AudioParameter(const String8& keyValuePairs);
|
||||
virtual ~AudioParameter();
|
||||
|
||||
// reserved parameter keys for changing standard parameters with setParameters() function.
|
||||
// Using these keys is mandatory for AudioFlinger to properly monitor audio output/input
|
||||
// configuration changes and act accordingly.
|
||||
// keyRouting: to change audio routing, value is an int in AudioSystem::audio_devices
|
||||
// keySamplingRate: to change sampling rate routing, value is an int
|
||||
// keyFormat: to change audio format, value is an int in AudioSystem::audio_format
|
||||
// keyChannels: to change audio channel configuration, value is an int in AudioSystem::audio_channels
|
||||
// keyFrameCount: to change audio output frame count, value is an int
|
||||
// keyInputSource: to change audio input source, value is an int in audio_source
|
||||
// (defined in media/mediarecorder.h)
|
||||
static const char *keyRouting;
|
||||
static const char *keySamplingRate;
|
||||
static const char *keyFormat;
|
||||
static const char *keyChannels;
|
||||
static const char *keyFrameCount;
|
||||
static const char *keyInputSource;
|
||||
|
||||
String8 toString();
|
||||
|
||||
status_t add(const String8& key, const String8& value);
|
||||
status_t addInt(const String8& key, const int value);
|
||||
status_t addFloat(const String8& key, const float value);
|
||||
|
||||
status_t remove(const String8& key);
|
||||
|
||||
status_t get(const String8& key, String8& value);
|
||||
status_t getInt(const String8& key, int& value);
|
||||
status_t getFloat(const String8& key, float& value);
|
||||
status_t getAt(size_t index, String8& key, String8& value);
|
||||
|
||||
size_t size() { return mParameters.size(); }
|
||||
|
||||
private:
|
||||
String8 mKeyValuePairs;
|
||||
KeyedVector <String8, String8> mParameters;
|
||||
};
|
||||
|
||||
}; // namespace android
|
||||
|
||||
#endif /*ANDROID_AUDIOSYSTEM_H_*/
|
|
@ -0,0 +1,488 @@
|
|||
/*
|
||||
* Copyright (C) 2007 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef ANDROID_AUDIOTRACK_H
|
||||
#define ANDROID_AUDIOTRACK_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "IAudioFlinger.h"
|
||||
#include "IAudioTrack.h"
|
||||
#include "AudioSystem.h"
|
||||
|
||||
#include <utils/RefBase.h>
|
||||
#include <utils/Errors.h>
|
||||
#include <binder/IInterface.h>
|
||||
#include <binder/IMemory.h>
|
||||
#include <utils/threads.h>
|
||||
|
||||
|
||||
namespace android {
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
class audio_track_cblk_t;
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
class AudioTrack
|
||||
{
|
||||
public:
|
||||
enum channel_index {
|
||||
MONO = 0,
|
||||
LEFT = 0,
|
||||
RIGHT = 1
|
||||
};
|
||||
|
||||
/* Events used by AudioTrack callback function (audio_track_cblk_t).
|
||||
*/
|
||||
enum event_type {
|
||||
EVENT_MORE_DATA = 0, // Request to write more data to PCM buffer.
|
||||
EVENT_UNDERRUN = 1, // PCM buffer underrun occured.
|
||||
EVENT_LOOP_END = 2, // Sample loop end was reached; playback restarted from loop start if loop count was not 0.
|
||||
EVENT_MARKER = 3, // Playback head is at the specified marker position (See setMarkerPosition()).
|
||||
EVENT_NEW_POS = 4, // Playback head is at a new position (See setPositionUpdatePeriod()).
|
||||
EVENT_BUFFER_END = 5 // Playback head is at the end of the buffer.
|
||||
};
|
||||
|
||||
/* Create Buffer on the stack and pass it to obtainBuffer()
|
||||
* and releaseBuffer().
|
||||
*/
|
||||
|
||||
class Buffer
|
||||
{
|
||||
public:
|
||||
enum {
|
||||
MUTE = 0x00000001
|
||||
};
|
||||
uint32_t flags;
|
||||
int channelCount;
|
||||
int format;
|
||||
size_t frameCount;
|
||||
size_t size;
|
||||
union {
|
||||
void* raw;
|
||||
short* i16;
|
||||
int8_t* i8;
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
/* As a convenience, if a callback is supplied, a handler thread
|
||||
* is automatically created with the appropriate priority. This thread
|
||||
* invokes the callback when a new buffer becomes availlable or an underrun condition occurs.
|
||||
* Parameters:
|
||||
*
|
||||
* event: type of event notified (see enum AudioTrack::event_type).
|
||||
* user: Pointer to context for use by the callback receiver.
|
||||
* info: Pointer to optional parameter according to event type:
|
||||
* - EVENT_MORE_DATA: pointer to AudioTrack::Buffer struct. The callback must not write
|
||||
* more bytes than indicated by 'size' field and update 'size' if less bytes are
|
||||
* written.
|
||||
* - EVENT_UNDERRUN: unused.
|
||||
* - EVENT_LOOP_END: pointer to an int indicating the number of loops remaining.
|
||||
* - EVENT_MARKER: pointer to an uin32_t containing the marker position in frames.
|
||||
* - EVENT_NEW_POS: pointer to an uin32_t containing the new position in frames.
|
||||
* - EVENT_BUFFER_END: unused.
|
||||
*/
|
||||
|
||||
typedef void (*callback_t)(int event, void* user, void *info);
|
||||
|
||||
/* Returns the minimum frame count required for the successful creation of
|
||||
* an AudioTrack object.
|
||||
* Returned status (from utils/Errors.h) can be:
|
||||
* - NO_ERROR: successful operation
|
||||
* - NO_INIT: audio server or audio hardware not initialized
|
||||
*/
|
||||
|
||||
static status_t getMinFrameCount(int* frameCount,
|
||||
int streamType =-1,
|
||||
uint32_t sampleRate = 0);
|
||||
|
||||
/* Constructs an uninitialized AudioTrack. No connection with
|
||||
* AudioFlinger takes place.
|
||||
*/
|
||||
AudioTrack();
|
||||
|
||||
/* Creates an audio track and registers it with AudioFlinger.
|
||||
* Once created, the track needs to be started before it can be used.
|
||||
* Unspecified values are set to the audio hardware's current
|
||||
* values.
|
||||
*
|
||||
* Parameters:
|
||||
*
|
||||
* streamType: Select the type of audio stream this track is attached to
|
||||
* (e.g. AudioSystem::MUSIC).
|
||||
* sampleRate: Track sampling rate in Hz.
|
||||
* format: Audio format (e.g AudioSystem::PCM_16_BIT for signed
|
||||
* 16 bits per sample).
|
||||
* channels: Channel mask: see AudioSystem::audio_channels.
|
||||
* frameCount: Total size of track PCM buffer in frames. This defines the
|
||||
* latency of the track.
|
||||
* flags: Reserved for future use.
|
||||
* cbf: Callback function. If not null, this function is called periodically
|
||||
* to request new PCM data.
|
||||
* notificationFrames: The callback function is called each time notificationFrames PCM
|
||||
* frames have been comsumed from track input buffer.
|
||||
* user Context for use by the callback receiver.
|
||||
*/
|
||||
|
||||
AudioTrack( int streamType,
|
||||
uint32_t sampleRate = 0,
|
||||
int format = 0,
|
||||
int channels = 0,
|
||||
int frameCount = 0,
|
||||
uint32_t flags = 0,
|
||||
callback_t cbf = 0,
|
||||
void* user = 0,
|
||||
int notificationFrames = 0,
|
||||
int sessionId = 0);
|
||||
|
||||
/* Creates an audio track and registers it with AudioFlinger. With this constructor,
|
||||
* The PCM data to be rendered by AudioTrack is passed in a shared memory buffer
|
||||
* identified by the argument sharedBuffer. This prototype is for static buffer playback.
|
||||
* PCM data must be present into memory before the AudioTrack is started.
|
||||
* The Write() and Flush() methods are not supported in this case.
|
||||
* It is recommented to pass a callback function to be notified of playback end by an
|
||||
* EVENT_UNDERRUN event.
|
||||
*/
|
||||
|
||||
AudioTrack( int streamType,
|
||||
uint32_t sampleRate = 0,
|
||||
int format = 0,
|
||||
int channels = 0,
|
||||
const sp<IMemory>& sharedBuffer = 0,
|
||||
uint32_t flags = 0,
|
||||
callback_t cbf = 0,
|
||||
void* user = 0,
|
||||
int notificationFrames = 0,
|
||||
int sessionId = 0);
|
||||
|
||||
/* Terminates the AudioTrack and unregisters it from AudioFlinger.
|
||||
* Also destroys all resources assotiated with the AudioTrack.
|
||||
*/
|
||||
~AudioTrack();
|
||||
|
||||
|
||||
/* Initialize an uninitialized AudioTrack.
|
||||
* Returned status (from utils/Errors.h) can be:
|
||||
* - NO_ERROR: successful intialization
|
||||
* - INVALID_OPERATION: AudioTrack is already intitialized
|
||||
* - BAD_VALUE: invalid parameter (channels, format, sampleRate...)
|
||||
* - NO_INIT: audio server or audio hardware not initialized
|
||||
* */
|
||||
status_t set(int streamType =-1,
|
||||
uint32_t sampleRate = 0,
|
||||
int format = 0,
|
||||
int channels = 0,
|
||||
int frameCount = 0,
|
||||
uint32_t flags = 0,
|
||||
callback_t cbf = 0,
|
||||
void* user = 0,
|
||||
int notificationFrames = 0,
|
||||
const sp<IMemory>& sharedBuffer = 0,
|
||||
bool threadCanCallJava = false,
|
||||
int sessionId = 0);
|
||||
|
||||
|
||||
/* Result of constructing the AudioTrack. This must be checked
|
||||
* before using any AudioTrack API (except for set()), using
|
||||
* an uninitialized AudioTrack produces undefined results.
|
||||
* See set() method above for possible return codes.
|
||||
*/
|
||||
status_t initCheck() const;
|
||||
|
||||
/* Returns this track's latency in milliseconds.
|
||||
* This includes the latency due to AudioTrack buffer size, AudioMixer (if any)
|
||||
* and audio hardware driver.
|
||||
*/
|
||||
uint32_t latency() const;
|
||||
|
||||
/* getters, see constructor */
|
||||
|
||||
int streamType() const;
|
||||
int format() const;
|
||||
int channelCount() const;
|
||||
uint32_t frameCount() const;
|
||||
int frameSize() const;
|
||||
sp<IMemory>& sharedBuffer();
|
||||
|
||||
|
||||
/* After it's created the track is not active. Call start() to
|
||||
* make it active. If set, the callback will start being called.
|
||||
*/
|
||||
void start();
|
||||
|
||||
/* Stop a track. If set, the callback will cease being called and
|
||||
* obtainBuffer returns STOPPED. Note that obtainBuffer() still works
|
||||
* and will fill up buffers until the pool is exhausted.
|
||||
*/
|
||||
void stop();
|
||||
bool stopped() const;
|
||||
|
||||
/* flush a stopped track. All pending buffers are discarded.
|
||||
* This function has no effect if the track is not stoped.
|
||||
*/
|
||||
void flush();
|
||||
|
||||
/* Pause a track. If set, the callback will cease being called and
|
||||
* obtainBuffer returns STOPPED. Note that obtainBuffer() still works
|
||||
* and will fill up buffers until the pool is exhausted.
|
||||
*/
|
||||
void pause();
|
||||
|
||||
/* mute or unmutes this track.
|
||||
* While mutted, the callback, if set, is still called.
|
||||
*/
|
||||
void mute(bool);
|
||||
bool muted() const;
|
||||
|
||||
|
||||
/* set volume for this track, mostly used for games' sound effects
|
||||
* left and right volumes. Levels must be <= 1.0.
|
||||
*/
|
||||
status_t setVolume(float left, float right);
|
||||
void getVolume(float* left, float* right);
|
||||
|
||||
/* set the send level for this track. An auxiliary effect should be attached
|
||||
* to the track with attachEffect(). Level must be <= 1.0.
|
||||
*/
|
||||
status_t setAuxEffectSendLevel(float level);
|
||||
void getAuxEffectSendLevel(float* level);
|
||||
|
||||
/* set sample rate for this track, mostly used for games' sound effects
|
||||
*/
|
||||
status_t setSampleRate(int sampleRate);
|
||||
uint32_t getSampleRate();
|
||||
|
||||
/* Enables looping and sets the start and end points of looping.
|
||||
*
|
||||
* Parameters:
|
||||
*
|
||||
* loopStart: loop start expressed as the number of PCM frames played since AudioTrack start.
|
||||
* loopEnd: loop end expressed as the number of PCM frames played since AudioTrack start.
|
||||
* loopCount: number of loops to execute. Calling setLoop() with loopCount == 0 cancels any pending or
|
||||
* active loop. loopCount = -1 means infinite looping.
|
||||
*
|
||||
* For proper operation the following condition must be respected:
|
||||
* (loopEnd-loopStart) <= framecount()
|
||||
*/
|
||||
status_t setLoop(uint32_t loopStart, uint32_t loopEnd, int loopCount);
|
||||
status_t getLoop(uint32_t *loopStart, uint32_t *loopEnd, int *loopCount);
|
||||
|
||||
|
||||
/* Sets marker position. When playback reaches the number of frames specified, a callback with event
|
||||
* type EVENT_MARKER is called. Calling setMarkerPosition with marker == 0 cancels marker notification
|
||||
* callback.
|
||||
* If the AudioTrack has been opened with no callback function associated, the operation will fail.
|
||||
*
|
||||
* Parameters:
|
||||
*
|
||||
* marker: marker position expressed in frames.
|
||||
*
|
||||
* Returned status (from utils/Errors.h) can be:
|
||||
* - NO_ERROR: successful operation
|
||||
* - INVALID_OPERATION: the AudioTrack has no callback installed.
|
||||
*/
|
||||
status_t setMarkerPosition(uint32_t marker);
|
||||
status_t getMarkerPosition(uint32_t *marker);
|
||||
|
||||
|
||||
/* Sets position update period. Every time the number of frames specified has been played,
|
||||
* a callback with event type EVENT_NEW_POS is called.
|
||||
* Calling setPositionUpdatePeriod with updatePeriod == 0 cancels new position notification
|
||||
* callback.
|
||||
* If the AudioTrack has been opened with no callback function associated, the operation will fail.
|
||||
*
|
||||
* Parameters:
|
||||
*
|
||||
* updatePeriod: position update notification period expressed in frames.
|
||||
*
|
||||
* Returned status (from utils/Errors.h) can be:
|
||||
* - NO_ERROR: successful operation
|
||||
* - INVALID_OPERATION: the AudioTrack has no callback installed.
|
||||
*/
|
||||
status_t setPositionUpdatePeriod(uint32_t updatePeriod);
|
||||
status_t getPositionUpdatePeriod(uint32_t *updatePeriod);
|
||||
|
||||
|
||||
/* Sets playback head position within AudioTrack buffer. The new position is specified
|
||||
* in number of frames.
|
||||
* This method must be called with the AudioTrack in paused or stopped state.
|
||||
* Note that the actual position set is <position> modulo the AudioTrack buffer size in frames.
|
||||
* Therefore using this method makes sense only when playing a "static" audio buffer
|
||||
* as opposed to streaming.
|
||||
* The getPosition() method on the other hand returns the total number of frames played since
|
||||
* playback start.
|
||||
*
|
||||
* Parameters:
|
||||
*
|
||||
* position: New playback head position within AudioTrack buffer.
|
||||
*
|
||||
* Returned status (from utils/Errors.h) can be:
|
||||
* - NO_ERROR: successful operation
|
||||
* - INVALID_OPERATION: the AudioTrack is not stopped.
|
||||
* - BAD_VALUE: The specified position is beyond the number of frames present in AudioTrack buffer
|
||||
*/
|
||||
status_t setPosition(uint32_t position);
|
||||
status_t getPosition(uint32_t *position);
|
||||
|
||||
/* Forces AudioTrack buffer full condition. When playing a static buffer, this method avoids
|
||||
* rewriting the buffer before restarting playback after a stop.
|
||||
* This method must be called with the AudioTrack in paused or stopped state.
|
||||
*
|
||||
* Returned status (from utils/Errors.h) can be:
|
||||
* - NO_ERROR: successful operation
|
||||
* - INVALID_OPERATION: the AudioTrack is not stopped.
|
||||
*/
|
||||
status_t reload();
|
||||
|
||||
/* returns a handle on the audio output used by this AudioTrack.
|
||||
*
|
||||
* Parameters:
|
||||
* none.
|
||||
*
|
||||
* Returned value:
|
||||
* handle on audio hardware output
|
||||
*/
|
||||
audio_io_handle_t getOutput();
|
||||
|
||||
/* returns the unique ID associated to this track.
|
||||
*
|
||||
* Parameters:
|
||||
* none.
|
||||
*
|
||||
* Returned value:
|
||||
* AudioTrack ID.
|
||||
*/
|
||||
int getSessionId();
|
||||
|
||||
|
||||
/* Attach track auxiliary output to specified effect. Used effectId = 0
|
||||
* to detach track from effect.
|
||||
*
|
||||
* Parameters:
|
||||
*
|
||||
* effectId: effectId obtained from AudioEffect::id().
|
||||
*
|
||||
* Returned status (from utils/Errors.h) can be:
|
||||
* - NO_ERROR: successful operation
|
||||
* - INVALID_OPERATION: the effect is not an auxiliary effect.
|
||||
* - BAD_VALUE: The specified effect ID is invalid
|
||||
*/
|
||||
status_t attachAuxEffect(int effectId);
|
||||
|
||||
/* obtains a buffer of "frameCount" frames. The buffer must be
|
||||
* filled entirely. If the track is stopped, obtainBuffer() returns
|
||||
* STOPPED instead of NO_ERROR as long as there are buffers availlable,
|
||||
* at which point NO_MORE_BUFFERS is returned.
|
||||
* Buffers will be returned until the pool (buffercount())
|
||||
* is exhausted, at which point obtainBuffer() will either block
|
||||
* or return WOULD_BLOCK depending on the value of the "blocking"
|
||||
* parameter.
|
||||
*/
|
||||
|
||||
enum {
|
||||
NO_MORE_BUFFERS = 0x80000001,
|
||||
STOPPED = 1
|
||||
};
|
||||
|
||||
status_t obtainBuffer(Buffer* audioBuffer, int32_t waitCount);
|
||||
void releaseBuffer(Buffer* audioBuffer);
|
||||
|
||||
|
||||
/* As a convenience we provide a write() interface to the audio buffer.
|
||||
* This is implemented on top of lockBuffer/unlockBuffer. For best
|
||||
* performance
|
||||
*
|
||||
*/
|
||||
ssize_t write(const void* buffer, size_t size);
|
||||
|
||||
/*
|
||||
* Dumps the state of an audio track.
|
||||
*/
|
||||
status_t dump(int fd, const Vector<String16>& args) const;
|
||||
|
||||
private:
|
||||
/* copying audio tracks is not allowed */
|
||||
AudioTrack(const AudioTrack& other);
|
||||
AudioTrack& operator = (const AudioTrack& other);
|
||||
|
||||
/* a small internal class to handle the callback */
|
||||
class AudioTrackThread : public Thread
|
||||
{
|
||||
public:
|
||||
AudioTrackThread(AudioTrack& receiver, bool bCanCallJava = false);
|
||||
private:
|
||||
friend class AudioTrack;
|
||||
virtual bool threadLoop();
|
||||
virtual status_t readyToRun();
|
||||
virtual void onFirstRef();
|
||||
AudioTrack& mReceiver;
|
||||
Mutex mLock;
|
||||
};
|
||||
|
||||
bool processAudioBuffer(const sp<AudioTrackThread>& thread);
|
||||
status_t createTrack(int streamType,
|
||||
uint32_t sampleRate,
|
||||
int format,
|
||||
int channelCount,
|
||||
int frameCount,
|
||||
uint32_t flags,
|
||||
const sp<IMemory>& sharedBuffer,
|
||||
audio_io_handle_t output,
|
||||
bool enforceFrameCount);
|
||||
|
||||
sp<IAudioTrack> mAudioTrack;
|
||||
sp<IMemory> mCblkMemory;
|
||||
sp<AudioTrackThread> mAudioTrackThread;
|
||||
|
||||
float mVolume[2];
|
||||
float mSendLevel;
|
||||
uint32_t mFrameCount;
|
||||
|
||||
audio_track_cblk_t* mCblk;
|
||||
uint8_t mStreamType;
|
||||
uint8_t mFormat;
|
||||
uint8_t mChannelCount;
|
||||
uint8_t mMuted;
|
||||
uint32_t mChannels;
|
||||
status_t mStatus;
|
||||
uint32_t mLatency;
|
||||
|
||||
volatile int32_t mActive;
|
||||
|
||||
callback_t mCbf;
|
||||
void* mUserData;
|
||||
uint32_t mNotificationFramesReq; // requested number of frames between each notification callback
|
||||
uint32_t mNotificationFramesAct; // actual number of frames between each notification callback
|
||||
sp<IMemory> mSharedBuffer;
|
||||
int mLoopCount;
|
||||
uint32_t mRemainingFrames;
|
||||
uint32_t mMarkerPosition;
|
||||
bool mMarkerReached;
|
||||
uint32_t mNewPosition;
|
||||
uint32_t mUpdatePeriod;
|
||||
uint32_t mFlags;
|
||||
int mSessionId;
|
||||
int mAuxEffectId;
|
||||
};
|
||||
|
||||
|
||||
}; // namespace android
|
||||
|
||||
#endif // ANDROID_AUDIOTRACK_H
|
|
@ -0,0 +1,796 @@
|
|||
/*
|
||||
* Copyright (C) 2010 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef ANDROID_EFFECTAPI_H_
|
||||
#define ANDROID_EFFECTAPI_H_
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdint.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#if __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/////////////////////////////////////////////////
|
||||
// Effect control interface
|
||||
/////////////////////////////////////////////////
|
||||
|
||||
// The effect control interface is exposed by each effect engine implementation. It consists of
|
||||
// a set of functions controlling the configuration, activation and process of the engine.
|
||||
// The functions are grouped in a structure of type effect_interface_s:
|
||||
// struct effect_interface_s {
|
||||
// effect_process_t process;
|
||||
// effect_command_t command;
|
||||
// };
|
||||
|
||||
|
||||
// effect_interface_t: Effect control interface handle.
|
||||
// The effect_interface_t serves two purposes regarding the implementation of the effect engine:
|
||||
// - 1 it is the address of a pointer to an effect_interface_s structure where the functions
|
||||
// of the effect control API for a particular effect are located.
|
||||
// - 2 it is the address of the context of a particular effect instance.
|
||||
// A typical implementation in the effect library would define a structure as follows:
|
||||
// struct effect_module_s {
|
||||
// const struct effect_interface_s *itfe;
|
||||
// effect_config_t config;
|
||||
// effect_context_t context;
|
||||
// }
|
||||
// The implementation of EffectCreate() function would then allocate a structure of this
|
||||
// type and return its address as effect_interface_t
|
||||
typedef struct effect_interface_s **effect_interface_t;
|
||||
|
||||
|
||||
// Effect API version 1.0
|
||||
#define EFFECT_API_VERSION 0x0100 // Format 0xMMmm MM: Major version, mm: minor version
|
||||
|
||||
// Maximum length of character strings in structures defines by this API.
|
||||
#define EFFECT_STRING_LEN_MAX 64
|
||||
|
||||
//
|
||||
//--- Effect descriptor structure effect_descriptor_t
|
||||
//
|
||||
|
||||
// Unique effect ID (can be generated from the following site:
|
||||
// http://www.itu.int/ITU-T/asn1/uuid.html)
|
||||
// This format is used for both "type" and "uuid" fields of the effect descriptor structure.
|
||||
// - When used for effect type and the engine is implementing and effect corresponding to a standard
|
||||
// OpenSL ES interface, this ID must be the one defined in OpenSLES_IID.h for that interface.
|
||||
// - When used as uuid, it should be a unique UUID for this particular implementation.
|
||||
typedef struct effect_uuid_s {
|
||||
uint32_t timeLow;
|
||||
uint16_t timeMid;
|
||||
uint16_t timeHiAndVersion;
|
||||
uint16_t clockSeq;
|
||||
uint8_t node[6];
|
||||
} effect_uuid_t;
|
||||
|
||||
// NULL UUID definition (matches SL_IID_NULL_)
|
||||
#define EFFECT_UUID_INITIALIZER { 0xec7178ec, 0xe5e1, 0x4432, 0xa3f4, \
|
||||
{ 0x46, 0x57, 0xe6, 0x79, 0x52, 0x10 } }
|
||||
static const effect_uuid_t EFFECT_UUID_NULL_ = EFFECT_UUID_INITIALIZER;
|
||||
const effect_uuid_t * const EFFECT_UUID_NULL = &EFFECT_UUID_NULL_;
|
||||
const char * const EFFECT_UUID_NULL_STR = "ec7178ec-e5e1-4432-a3f4-4657e6795210";
|
||||
|
||||
// The effect descriptor contains necessary information to facilitate the enumeration of the effect
|
||||
// engines present in a library.
|
||||
typedef struct effect_descriptor_s {
|
||||
effect_uuid_t type; // UUID of to the OpenSL ES interface implemented by this effect
|
||||
effect_uuid_t uuid; // UUID for this particular implementation
|
||||
uint16_t apiVersion; // Version of the effect API implemented: matches EFFECT_API_VERSION
|
||||
uint32_t flags; // effect engine capabilities/requirements flags (see below)
|
||||
uint16_t cpuLoad; // CPU load indication (see below)
|
||||
uint16_t memoryUsage; // Data Memory usage (see below)
|
||||
char name[EFFECT_STRING_LEN_MAX]; // human readable effect name
|
||||
char implementor[EFFECT_STRING_LEN_MAX]; // human readable effect implementor name
|
||||
} effect_descriptor_t;
|
||||
|
||||
// CPU load and memory usage indication: each effect implementation must provide an indication of
|
||||
// its CPU and memory usage for the audio effect framework to limit the number of effects
|
||||
// instantiated at a given time on a given platform.
|
||||
// The CPU load is expressed in 0.1 MIPS units as estimated on an ARM9E core (ARMv5TE) with 0 WS.
|
||||
// The memory usage is expressed in KB and includes only dynamically allocated memory
|
||||
|
||||
// Definitions for flags field of effect descriptor.
|
||||
// +---------------------------+-----------+-----------------------------------
|
||||
// | description | bits | values
|
||||
// +---------------------------+-----------+-----------------------------------
|
||||
// | connection mode | 0..1 | 0 insert: after track process
|
||||
// | | | 1 auxiliary: connect to track auxiliary
|
||||
// | | | output and use send level
|
||||
// | | | 2 replace: replaces track process function;
|
||||
// | | | must implement SRC, volume and mono to stereo.
|
||||
// | | | 3 reserved
|
||||
// +---------------------------+-----------+-----------------------------------
|
||||
// | insertion preference | 2..4 | 0 none
|
||||
// | | | 1 first of the chain
|
||||
// | | | 2 last of the chain
|
||||
// | | | 3 exclusive (only effect in the insert chain)
|
||||
// | | | 4..7 reserved
|
||||
// +---------------------------+-----------+-----------------------------------
|
||||
// | Volume management | 5..6 | 0 none
|
||||
// | | | 1 implements volume control
|
||||
// | | | 2 requires volume indication
|
||||
// | | | 3 reserved
|
||||
// +---------------------------+-----------+-----------------------------------
|
||||
// | Device indication | 7..8 | 0 none
|
||||
// | | | 1 requires device updates
|
||||
// | | | 2..3 reserved
|
||||
// +---------------------------+-----------+-----------------------------------
|
||||
// | Sample input mode | 9..10 | 0 direct: process() function or EFFECT_CMD_CONFIGURE
|
||||
// | | | command must specify a buffer descriptor
|
||||
// | | | 1 provider: process() function uses the
|
||||
// | | | bufferProvider indicated by the
|
||||
// | | | EFFECT_CMD_CONFIGURE command to request input.
|
||||
// | | | buffers.
|
||||
// | | | 2 both: both input modes are supported
|
||||
// | | | 3 reserved
|
||||
// +---------------------------+-----------+-----------------------------------
|
||||
// | Sample output mode | 11..12 | 0 direct: process() function or EFFECT_CMD_CONFIGURE
|
||||
// | | | command must specify a buffer descriptor
|
||||
// | | | 1 provider: process() function uses the
|
||||
// | | | bufferProvider indicated by the
|
||||
// | | | EFFECT_CMD_CONFIGURE command to request output
|
||||
// | | | buffers.
|
||||
// | | | 2 both: both output modes are supported
|
||||
// | | | 3 reserved
|
||||
// +---------------------------+-----------+-----------------------------------
|
||||
// | Hardware acceleration | 13..15 | 0 No hardware acceleration
|
||||
// | | | 1 non tunneled hw acceleration: the process() function
|
||||
// | | | reads the samples, send them to HW accelerated
|
||||
// | | | effect processor, reads back the processed samples
|
||||
// | | | and returns them to the output buffer.
|
||||
// | | | 2 tunneled hw acceleration: the process() function is
|
||||
// | | | transparent. The effect interface is only used to
|
||||
// | | | control the effect engine. This mode is relevant for
|
||||
// | | | global effects actually applied by the audio
|
||||
// | | | hardware on the output stream.
|
||||
// +---------------------------+-----------+-----------------------------------
|
||||
// | Audio Mode indication | 16..17 | 0 none
|
||||
// | | | 1 requires audio mode updates
|
||||
// | | | 2..3 reserved
|
||||
// +---------------------------+-----------+-----------------------------------
|
||||
|
||||
// Insert mode
|
||||
#define EFFECT_FLAG_TYPE_MASK 0x00000003
|
||||
#define EFFECT_FLAG_TYPE_INSERT 0x00000000
|
||||
#define EFFECT_FLAG_TYPE_AUXILIARY 0x00000001
|
||||
#define EFFECT_FLAG_TYPE_REPLACE 0x00000002
|
||||
|
||||
// Insert preference
|
||||
#define EFFECT_FLAG_INSERT_MASK 0x0000001C
|
||||
#define EFFECT_FLAG_INSERT_ANY 0x00000000
|
||||
#define EFFECT_FLAG_INSERT_FIRST 0x00000004
|
||||
#define EFFECT_FLAG_INSERT_LAST 0x00000008
|
||||
#define EFFECT_FLAG_INSERT_EXCLUSIVE 0x0000000C
|
||||
|
||||
|
||||
// Volume control
|
||||
#define EFFECT_FLAG_VOLUME_MASK 0x00000060
|
||||
#define EFFECT_FLAG_VOLUME_CTRL 0x00000020
|
||||
#define EFFECT_FLAG_VOLUME_IND 0x00000040
|
||||
#define EFFECT_FLAG_VOLUME_NONE 0x00000000
|
||||
|
||||
// Device indication
|
||||
#define EFFECT_FLAG_DEVICE_MASK 0x00000180
|
||||
#define EFFECT_FLAG_DEVICE_IND 0x00000080
|
||||
#define EFFECT_FLAG_DEVICE_NONE 0x00000000
|
||||
|
||||
// Sample input modes
|
||||
#define EFFECT_FLAG_INPUT_MASK 0x00000600
|
||||
#define EFFECT_FLAG_INPUT_DIRECT 0x00000000
|
||||
#define EFFECT_FLAG_INPUT_PROVIDER 0x00000200
|
||||
#define EFFECT_FLAG_INPUT_BOTH 0x00000400
|
||||
|
||||
// Sample output modes
|
||||
#define EFFECT_FLAG_OUTPUT_MASK 0x00001800
|
||||
#define EFFECT_FLAG_OUTPUT_DIRECT 0x00000000
|
||||
#define EFFECT_FLAG_OUTPUT_PROVIDER 0x00000800
|
||||
#define EFFECT_FLAG_OUTPUT_BOTH 0x00001000
|
||||
|
||||
// Hardware acceleration mode
|
||||
#define EFFECT_FLAG_HW_ACC_MASK 0x00006000
|
||||
#define EFFECT_FLAG_HW_ACC_SIMPLE 0x00002000
|
||||
#define EFFECT_FLAG_HW_ACC_TUNNEL 0x00004000
|
||||
|
||||
// Audio mode indication
|
||||
#define EFFECT_FLAG_AUDIO_MODE_MASK 0x00018000
|
||||
#define EFFECT_FLAG_AUDIO_MODE_IND 0x00008000
|
||||
#define EFFECT_FLAG_AUDIO_MODE_NONE 0x00000000
|
||||
|
||||
// Forward definition of type audio_buffer_t
|
||||
typedef struct audio_buffer_s audio_buffer_t;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Function: process
|
||||
//
|
||||
// Description: Effect process function. Takes input samples as specified
|
||||
// (count and location) in input buffer descriptor and output processed
|
||||
// samples as specified in output buffer descriptor. If the buffer descriptor
|
||||
// is not specified the function must use either the buffer or the
|
||||
// buffer provider function installed by the EFFECT_CMD_CONFIGURE command.
|
||||
// The effect framework will call the process() function after the EFFECT_CMD_ENABLE
|
||||
// command is received and until the EFFECT_CMD_DISABLE is received. When the engine
|
||||
// receives the EFFECT_CMD_DISABLE command it should turn off the effect gracefully
|
||||
// and when done indicate that it is OK to stop calling the process() function by
|
||||
// returning the -ENODATA status.
|
||||
//
|
||||
// NOTE: the process() function implementation should be "real-time safe" that is
|
||||
// it should not perform blocking calls: malloc/free, sleep, read/write/open/close,
|
||||
// pthread_cond_wait/pthread_mutex_lock...
|
||||
//
|
||||
// Input:
|
||||
// effect_interface_t: handle to the effect interface this function
|
||||
// is called on.
|
||||
// inBuffer: buffer descriptor indicating where to read samples to process.
|
||||
// If NULL, use the configuration passed by EFFECT_CMD_CONFIGURE command.
|
||||
//
|
||||
// inBuffer: buffer descriptor indicating where to write processed samples.
|
||||
// If NULL, use the configuration passed by EFFECT_CMD_CONFIGURE command.
|
||||
//
|
||||
// Output:
|
||||
// returned value: 0 successful operation
|
||||
// -ENODATA the engine has finished the disable phase and the framework
|
||||
// can stop calling process()
|
||||
// -EINVAL invalid interface handle or
|
||||
// invalid input/output buffer description
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
typedef int32_t (*effect_process_t)(effect_interface_t self,
|
||||
audio_buffer_t *inBuffer,
|
||||
audio_buffer_t *outBuffer);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Function: command
|
||||
//
|
||||
// Description: Send a command and receive a response to/from effect engine.
|
||||
//
|
||||
// Input:
|
||||
// effect_interface_t: handle to the effect interface this function
|
||||
// is called on.
|
||||
// cmdCode: command code: the command can be a standardized command defined in
|
||||
// effect_command_e (see below) or a proprietary command.
|
||||
// cmdSize: size of command in bytes
|
||||
// pCmdData: pointer to command data
|
||||
// pReplyData: pointer to reply data
|
||||
//
|
||||
// Input/Output:
|
||||
// replySize: maximum size of reply data as input
|
||||
// actual size of reply data as output
|
||||
//
|
||||
// Output:
|
||||
// returned value: 0 successful operation
|
||||
// -EINVAL invalid interface handle or
|
||||
// invalid command/reply size or format according to command code
|
||||
// The return code should be restricted to indicate problems related to the this
|
||||
// API specification. Status related to the execution of a particular command should be
|
||||
// indicated as part of the reply field.
|
||||
//
|
||||
// *pReplyData updated with command response
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
typedef int32_t (*effect_command_t)(effect_interface_t self,
|
||||
uint32_t cmdCode,
|
||||
uint32_t cmdSize,
|
||||
void *pCmdData,
|
||||
uint32_t *replySize,
|
||||
void *pReplyData);
|
||||
|
||||
|
||||
// Effect control interface definition
|
||||
struct effect_interface_s {
|
||||
effect_process_t process;
|
||||
effect_command_t command;
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
//--- Standardized command codes for command() function
|
||||
//
|
||||
enum effect_command_e {
|
||||
EFFECT_CMD_INIT, // initialize effect engine
|
||||
EFFECT_CMD_CONFIGURE, // configure effect engine (see effect_config_t)
|
||||
EFFECT_CMD_RESET, // reset effect engine
|
||||
EFFECT_CMD_ENABLE, // enable effect process
|
||||
EFFECT_CMD_DISABLE, // disable effect process
|
||||
EFFECT_CMD_SET_PARAM, // set parameter immediately (see effect_param_t)
|
||||
EFFECT_CMD_SET_PARAM_DEFERRED, // set parameter deferred
|
||||
EFFECT_CMD_SET_PARAM_COMMIT, // commit previous set parameter deferred
|
||||
EFFECT_CMD_GET_PARAM, // get parameter
|
||||
EFFECT_CMD_SET_DEVICE, // set audio device (see audio_device_e)
|
||||
EFFECT_CMD_SET_VOLUME, // set volume
|
||||
EFFECT_CMD_SET_AUDIO_MODE, // set the audio mode (normal, ring, ...)
|
||||
EFFECT_CMD_FIRST_PROPRIETARY = 0x10000 // first proprietary command code
|
||||
};
|
||||
|
||||
//==================================================================================================
|
||||
// command: EFFECT_CMD_INIT
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
// description:
|
||||
// Initialize effect engine: All configurations return to default
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
// command format:
|
||||
// size: 0
|
||||
// data: N/A
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
// reply format:
|
||||
// size: sizeof(int)
|
||||
// data: status
|
||||
//==================================================================================================
|
||||
// command: EFFECT_CMD_CONFIGURE
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
// description:
|
||||
// Apply new audio parameters configurations for input and output buffers
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
// command format:
|
||||
// size: sizeof(effect_config_t)
|
||||
// data: effect_config_t
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
// reply format:
|
||||
// size: sizeof(int)
|
||||
// data: status
|
||||
//==================================================================================================
|
||||
// command: EFFECT_CMD_RESET
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
// description:
|
||||
// Reset the effect engine. Keep configuration but resets state and buffer content
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
// command format:
|
||||
// size: 0
|
||||
// data: N/A
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
// reply format:
|
||||
// size: 0
|
||||
// data: N/A
|
||||
//==================================================================================================
|
||||
// command: EFFECT_CMD_ENABLE
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
// description:
|
||||
// Enable the process. Called by the framework before the first call to process()
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
// command format:
|
||||
// size: 0
|
||||
// data: N/A
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
// reply format:
|
||||
// size: sizeof(int)
|
||||
// data: status
|
||||
//==================================================================================================
|
||||
// command: EFFECT_CMD_DISABLE
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
// description:
|
||||
// Disable the process. Called by the framework after the last call to process()
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
// command format:
|
||||
// size: 0
|
||||
// data: N/A
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
// reply format:
|
||||
// size: sizeof(int)
|
||||
// data: status
|
||||
//==================================================================================================
|
||||
// command: EFFECT_CMD_SET_PARAM
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
// description:
|
||||
// Set a parameter and apply it immediately
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
// command format:
|
||||
// size: sizeof(effect_param_t) + size of param and value
|
||||
// data: effect_param_t + param + value. See effect_param_t definition below for value offset
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
// reply format:
|
||||
// size: sizeof(int)
|
||||
// data: status
|
||||
//==================================================================================================
|
||||
// command: EFFECT_CMD_SET_PARAM_DEFERRED
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
// description:
|
||||
// Set a parameter but apply it only when receiving EFFECT_CMD_SET_PARAM_COMMIT command
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
// command format:
|
||||
// size: sizeof(effect_param_t) + size of param and value
|
||||
// data: effect_param_t + param + value. See effect_param_t definition below for value offset
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
// reply format:
|
||||
// size: 0
|
||||
// data: N/A
|
||||
//==================================================================================================
|
||||
// command: EFFECT_CMD_SET_PARAM_COMMIT
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
// description:
|
||||
// Apply all previously received EFFECT_CMD_SET_PARAM_DEFERRED commands
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
// command format:
|
||||
// size: 0
|
||||
// data: N/A
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
// reply format:
|
||||
// size: sizeof(int)
|
||||
// data: status
|
||||
//==================================================================================================
|
||||
// command: EFFECT_CMD_GET_PARAM
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
// description:
|
||||
// Get a parameter value
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
// command format:
|
||||
// size: sizeof(effect_param_t) + size of param
|
||||
// data: effect_param_t + param
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
// reply format:
|
||||
// size: sizeof(effect_param_t) + size of param and value
|
||||
// data: effect_param_t + param + value. See effect_param_t definition below for value offset
|
||||
//==================================================================================================
|
||||
// command: EFFECT_CMD_SET_DEVICE
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
// description:
|
||||
// Set the rendering device the audio output path is connected to. See audio_device_e for device
|
||||
// values.
|
||||
// The effect implementation must set EFFECT_FLAG_DEVICE_IND flag in its descriptor to receive this
|
||||
// command when the device changes
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
// command format:
|
||||
// size: sizeof(uint32_t)
|
||||
// data: audio_device_e
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
// reply format:
|
||||
// size: 0
|
||||
// data: N/A
|
||||
//==================================================================================================
|
||||
// command: EFFECT_CMD_SET_VOLUME
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
// description:
|
||||
// Set and get volume. Used by audio framework to delegate volume control to effect engine.
|
||||
// The effect implementation must set EFFECT_FLAG_VOLUME_IND or EFFECT_FLAG_VOLUME_CTRL flag in
|
||||
// its descriptor to receive this command before every call to process() function
|
||||
// If EFFECT_FLAG_VOLUME_CTRL flag is set in the effect descriptor, the effect engine must return
|
||||
// the volume that should be applied before the effect is processed. The overall volume (the volume
|
||||
// actually applied by the effect engine multiplied by the returned value) should match the value
|
||||
// indicated in the command.
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
// command format:
|
||||
// size: n * sizeof(uint32_t)
|
||||
// data: volume for each channel defined in effect_config_t for output buffer expressed in
|
||||
// 8.24 fixed point format
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
// reply format:
|
||||
// size: n * sizeof(uint32_t) / 0
|
||||
// data: - if EFFECT_FLAG_VOLUME_CTRL is set in effect descriptor:
|
||||
// volume for each channel defined in effect_config_t for output buffer expressed in
|
||||
// 8.24 fixed point format
|
||||
// - if EFFECT_FLAG_VOLUME_CTRL is not set in effect descriptor:
|
||||
// N/A
|
||||
// It is legal to receive a null pointer as pReplyData in which case the effect framework has
|
||||
// delegated volume control to another effect
|
||||
//==================================================================================================
|
||||
// command: EFFECT_CMD_SET_AUDIO_MODE
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
// description:
|
||||
// Set the audio mode. The effect implementation must set EFFECT_FLAG_AUDIO_MODE_IND flag in its
|
||||
// descriptor to receive this command when the audio mode changes.
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
// command format:
|
||||
// size: sizeof(uint32_t)
|
||||
// data: audio_mode_e
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
// reply format:
|
||||
// size: 0
|
||||
// data: N/A
|
||||
//==================================================================================================
|
||||
// command: EFFECT_CMD_FIRST_PROPRIETARY
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
// description:
|
||||
// All proprietary effect commands must use command codes above this value. The size and format of
|
||||
// command and response fields is free in this case
|
||||
//==================================================================================================
|
||||
|
||||
|
||||
// Audio buffer descriptor used by process(), bufferProvider() functions and buffer_config_t
|
||||
// structure. Multi-channel audio is always interleaved. The channel order is from LSB to MSB with
|
||||
// regard to the channel mask definition in audio_channels_e e.g :
|
||||
// Stereo: left, right
|
||||
// 5 point 1: front left, front right, front center, low frequency, back left, back right
|
||||
// The buffer size is expressed in frame count, a frame being composed of samples for all
|
||||
// channels at a given time. Frame size for unspecified format (AUDIO_FORMAT_OTHER) is 8 bit by
|
||||
// definition
|
||||
struct audio_buffer_s {
|
||||
size_t frameCount; // number of frames in buffer
|
||||
union {
|
||||
void* raw; // raw pointer to start of buffer
|
||||
int32_t* s32; // pointer to signed 32 bit data at start of buffer
|
||||
int16_t* s16; // pointer to signed 16 bit data at start of buffer
|
||||
uint8_t* u8; // pointer to unsigned 8 bit data at start of buffer
|
||||
};
|
||||
};
|
||||
|
||||
// The buffer_provider_s structure contains functions that can be used
|
||||
// by the effect engine process() function to query and release input
|
||||
// or output audio buffer.
|
||||
// The getBuffer() function is called to retrieve a buffer where data
|
||||
// should read from or written to by process() function.
|
||||
// The releaseBuffer() function MUST be called when the buffer retrieved
|
||||
// with getBuffer() is not needed anymore.
|
||||
// The process function should use the buffer provider mechanism to retrieve
|
||||
// input or output buffer if the inBuffer or outBuffer passed as argument is NULL
|
||||
// and the buffer configuration (buffer_config_t) given by the EFFECT_CMD_CONFIGURE
|
||||
// command did not specify an audio buffer.
|
||||
|
||||
typedef int32_t (* buffer_function_t)(void *cookie, audio_buffer_t *buffer);
|
||||
|
||||
typedef struct buffer_provider_s {
|
||||
buffer_function_t getBuffer; // retrieve next buffer
|
||||
buffer_function_t releaseBuffer; // release used buffer
|
||||
void *cookie; // for use by client of buffer provider functions
|
||||
} buffer_provider_t;
|
||||
|
||||
|
||||
// The buffer_config_s structure specifies the input or output audio format
|
||||
// to be used by the effect engine. It is part of the effect_config_t
|
||||
// structure that defines both input and output buffer configurations and is
|
||||
// passed by the EFFECT_CMD_CONFIGURE command.
|
||||
typedef struct buffer_config_s {
|
||||
audio_buffer_t buffer; // buffer for use by process() function if not passed explicitly
|
||||
uint32_t samplingRate; // sampling rate
|
||||
uint32_t channels; // channel mask (see audio_channels_e)
|
||||
buffer_provider_t bufferProvider; // buffer provider
|
||||
uint8_t format; // Audio format (see audio_format_e)
|
||||
uint8_t accessMode; // read/write or accumulate in buffer (effect_buffer_access_e)
|
||||
uint16_t mask; // indicates which of the above fields is valid
|
||||
} buffer_config_t;
|
||||
|
||||
// Sample format
|
||||
enum audio_format_e {
|
||||
SAMPLE_FORMAT_PCM_S15, // PCM signed 16 bits
|
||||
SAMPLE_FORMAT_PCM_U8, // PCM unsigned 8 bits
|
||||
SAMPLE_FORMAT_PCM_S7_24, // PCM signed 7.24 fixed point representation
|
||||
SAMPLE_FORMAT_OTHER // other format (e.g. compressed)
|
||||
};
|
||||
|
||||
// Channel mask
|
||||
enum audio_channels_e {
|
||||
CHANNEL_FRONT_LEFT = 0x1, // front left channel
|
||||
CHANNEL_FRONT_RIGHT = 0x2, // front right channel
|
||||
CHANNEL_FRONT_CENTER = 0x4, // front center channel
|
||||
CHANNEL_LOW_FREQUENCY = 0x8, // low frequency channel
|
||||
CHANNEL_BACK_LEFT = 0x10, // back left channel
|
||||
CHANNEL_BACK_RIGHT = 0x20, // back right channel
|
||||
CHANNEL_FRONT_LEFT_OF_CENTER = 0x40, // front left of center channel
|
||||
CHANNEL_FRONT_RIGHT_OF_CENTER = 0x80, // front right of center channel
|
||||
CHANNEL_BACK_CENTER = 0x100, // back center channel
|
||||
CHANNEL_MONO = CHANNEL_FRONT_LEFT,
|
||||
CHANNEL_STEREO = (CHANNEL_FRONT_LEFT | CHANNEL_FRONT_RIGHT),
|
||||
CHANNEL_QUAD = (CHANNEL_FRONT_LEFT | CHANNEL_FRONT_RIGHT |
|
||||
CHANNEL_BACK_LEFT | CHANNEL_BACK_RIGHT),
|
||||
CHANNEL_SURROUND = (CHANNEL_FRONT_LEFT | CHANNEL_FRONT_RIGHT |
|
||||
CHANNEL_FRONT_CENTER | CHANNEL_BACK_CENTER),
|
||||
CHANNEL_5POINT1 = (CHANNEL_FRONT_LEFT | CHANNEL_FRONT_RIGHT |
|
||||
CHANNEL_FRONT_CENTER | CHANNEL_LOW_FREQUENCY | CHANNEL_BACK_LEFT | CHANNEL_BACK_RIGHT),
|
||||
CHANNEL_7POINT1 = (CHANNEL_FRONT_LEFT | CHANNEL_FRONT_RIGHT |
|
||||
CHANNEL_FRONT_CENTER | CHANNEL_LOW_FREQUENCY | CHANNEL_BACK_LEFT | CHANNEL_BACK_RIGHT |
|
||||
CHANNEL_FRONT_LEFT_OF_CENTER | CHANNEL_FRONT_RIGHT_OF_CENTER),
|
||||
};
|
||||
|
||||
// Render device
|
||||
enum audio_device_e {
|
||||
DEVICE_EARPIECE = 0x1, // earpiece
|
||||
DEVICE_SPEAKER = 0x2, // speaker
|
||||
DEVICE_WIRED_HEADSET = 0x4, // wired headset, with microphone
|
||||
DEVICE_WIRED_HEADPHONE = 0x8, // wired headphone, without microphone
|
||||
DEVICE_BLUETOOTH_SCO = 0x10, // generic bluetooth SCO
|
||||
DEVICE_BLUETOOTH_SCO_HEADSET = 0x20, // bluetooth SCO headset
|
||||
DEVICE_BLUETOOTH_SCO_CARKIT = 0x40, // bluetooth SCO car kit
|
||||
DEVICE_BLUETOOTH_A2DP = 0x80, // generic bluetooth A2DP
|
||||
DEVICE_BLUETOOTH_A2DP_HEADPHONES = 0x100, // bluetooth A2DP headphones
|
||||
DEVICE_BLUETOOTH_A2DP_SPEAKER = 0x200, // bluetooth A2DP speakers
|
||||
DEVICE_AUX_DIGITAL = 0x400, // digital output
|
||||
DEVICE_EXTERNAL_SPEAKER = 0x800 // external speaker (stereo and High quality)
|
||||
};
|
||||
|
||||
// Audio mode
|
||||
enum audio_mode_e {
|
||||
AUDIO_MODE_NORMAL, // device idle
|
||||
AUDIO_MODE_RINGTONE, // device ringing
|
||||
AUDIO_MODE_IN_CALL // audio call connected (VoIP or telephony)
|
||||
};
|
||||
|
||||
// Values for "accessMode" field of buffer_config_t:
|
||||
// overwrite, read only, accumulate (read/modify/write)
|
||||
enum effect_buffer_access_e {
|
||||
EFFECT_BUFFER_ACCESS_WRITE,
|
||||
EFFECT_BUFFER_ACCESS_READ,
|
||||
EFFECT_BUFFER_ACCESS_ACCUMULATE
|
||||
|
||||
};
|
||||
|
||||
// Values for bit field "mask" in buffer_config_t. If a bit is set, the corresponding field
|
||||
// in buffer_config_t must be taken into account when executing the EFFECT_CMD_CONFIGURE command
|
||||
#define EFFECT_CONFIG_BUFFER 0x0001 // buffer field must be taken into account
|
||||
#define EFFECT_CONFIG_SMP_RATE 0x0002 // samplingRate field must be taken into account
|
||||
#define EFFECT_CONFIG_CHANNELS 0x0004 // channels field must be taken into account
|
||||
#define EFFECT_CONFIG_FORMAT 0x0008 // format field must be taken into account
|
||||
#define EFFECT_CONFIG_ACC_MODE 0x0010 // accessMode field must be taken into account
|
||||
#define EFFECT_CONFIG_PROVIDER 0x0020 // bufferProvider field must be taken into account
|
||||
#define EFFECT_CONFIG_ALL (EFFECT_CONFIG_BUFFER | EFFECT_CONFIG_SMP_RATE | \
|
||||
EFFECT_CONFIG_CHANNELS | EFFECT_CONFIG_FORMAT | \
|
||||
EFFECT_CONFIG_ACC_MODE | EFFECT_CONFIG_PROVIDER)
|
||||
|
||||
|
||||
// effect_config_s structure describes the format of the pCmdData argument of EFFECT_CMD_CONFIGURE
|
||||
// command to configure audio parameters and buffers for effect engine input and output.
|
||||
typedef struct effect_config_s {
|
||||
buffer_config_t inputCfg;
|
||||
buffer_config_t outputCfg;;
|
||||
} effect_config_t;
|
||||
|
||||
|
||||
// effect_param_s structure describes the format of the pCmdData argument of EFFECT_CMD_SET_PARAM
|
||||
// command and pCmdData and pReplyData of EFFECT_CMD_GET_PARAM command.
|
||||
// psize and vsize represent the actual size of parameter and value.
|
||||
//
|
||||
// NOTE: the start of value field inside the data field is always on a 32 bit boundary:
|
||||
//
|
||||
// +-----------+
|
||||
// | status | sizeof(int)
|
||||
// +-----------+
|
||||
// | psize | sizeof(int)
|
||||
// +-----------+
|
||||
// | vsize | sizeof(int)
|
||||
// +-----------+
|
||||
// | | | |
|
||||
// ~ parameter ~ > psize |
|
||||
// | | | > ((psize - 1)/sizeof(int) + 1) * sizeof(int)
|
||||
// +-----------+ |
|
||||
// | padding | |
|
||||
// +-----------+
|
||||
// | | |
|
||||
// ~ value ~ > vsize
|
||||
// | | |
|
||||
// +-----------+
|
||||
|
||||
typedef struct effect_param_s {
|
||||
int32_t status; // Transaction status (unused for command, used for reply)
|
||||
uint32_t psize; // Parameter size
|
||||
uint32_t vsize; // Value size
|
||||
char data[]; // Start of Parameter + Value data
|
||||
} effect_param_t;
|
||||
|
||||
|
||||
/////////////////////////////////////////////////
|
||||
// Effect library interface
|
||||
/////////////////////////////////////////////////
|
||||
|
||||
// An effect library is required to implement and expose the following functions
|
||||
// to enable effect enumeration and instantiation. The name of these functions must be as
|
||||
// specified here as the effect framework will get the function address with dlsym():
|
||||
//
|
||||
// - effect_QueryNumberEffects_t EffectQueryNumberEffects;
|
||||
// - effect_QueryEffect_t EffectQueryEffect;
|
||||
// - effect_CreateEffect_t EffectCreate;
|
||||
// - effect_ReleaseEffect_t EffectRelease;
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Function: EffectQueryNumberEffects
|
||||
//
|
||||
// Description: Returns the number of different effects exposed by the
|
||||
// library. Each effect must have a unique effect uuid (see
|
||||
// effect_descriptor_t). This function together with EffectQueryEffect()
|
||||
// is used to enumerate all effects present in the library.
|
||||
//
|
||||
// Input/Output:
|
||||
// pNumEffects: address where the number of effects should be returned.
|
||||
//
|
||||
// Output:
|
||||
// returned value: 0 successful operation.
|
||||
// -ENODEV library failed to initialize
|
||||
// -EINVAL invalid pNumEffects
|
||||
// *pNumEffects: updated with number of effects in library
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
typedef int32_t (*effect_QueryNumberEffects_t)(uint32_t *pNumEffects);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Function: EffectQueryEffect
|
||||
//
|
||||
// Description: Returns the descriptor of the effect engine which index is
|
||||
// given as first argument.
|
||||
// See effect_descriptor_t for details on effect descriptors.
|
||||
// This function together with EffectQueryNumberEffects() is used to enumerate all
|
||||
// effects present in the library. The enumeration sequence is:
|
||||
// EffectQueryNumberEffects(&num_effects);
|
||||
// for (i = 0; i < num_effects; i++)
|
||||
// EffectQueryEffect(i,...);
|
||||
//
|
||||
// Input/Output:
|
||||
// index: index of the effect
|
||||
// pDescriptor: address where to return the effect descriptor.
|
||||
//
|
||||
// Output:
|
||||
// returned value: 0 successful operation.
|
||||
// -ENODEV library failed to initialize
|
||||
// -EINVAL invalid pDescriptor or index
|
||||
// -ENOSYS effect list has changed since last execution of
|
||||
// EffectQueryNumberEffects()
|
||||
// -ENOENT no more effect available
|
||||
// *pDescriptor: updated with the effect descriptor.
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
typedef int32_t (*effect_QueryEffect_t)(uint32_t index,
|
||||
effect_descriptor_t *pDescriptor);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Function: EffectCreate
|
||||
//
|
||||
// Description: Creates an effect engine of the specified type and returns an
|
||||
// effect control interface on this engine. The function will allocate the
|
||||
// resources for an instance of the requested effect engine and return
|
||||
// a handle on the effect control interface.
|
||||
//
|
||||
// Input:
|
||||
// uuid: pointer to the effect uuid.
|
||||
// sessionId: audio session to which this effect instance will be attached. All effects
|
||||
// created with the same session ID are connected in series and process the same signal
|
||||
// stream. Knowing that two effects are part of the same effect chain can help the
|
||||
// library implement some kind of optimizations.
|
||||
// ioId: identifies the output or input stream this effect is directed to at audio HAL.
|
||||
// For future use especially with tunneled HW accelerated effects
|
||||
//
|
||||
// Input/Output:
|
||||
// pInterface: address where to return the effect interface.
|
||||
//
|
||||
// Output:
|
||||
// returned value: 0 successful operation.
|
||||
// -ENODEV library failed to initialize
|
||||
// -EINVAL invalid pEffectUuid or pInterface
|
||||
// -ENOENT no effect with this uuid found
|
||||
// *pInterface: updated with the effect interface handle.
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
typedef int32_t (*effect_CreateEffect_t)(effect_uuid_t *uuid,
|
||||
int32_t sessionId,
|
||||
int32_t ioId,
|
||||
effect_interface_t *pInterface);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Function: EffectRelease
|
||||
//
|
||||
// Description: Releases the effect engine whose handle is given as argument.
|
||||
// All resources allocated to this particular instance of the effect are
|
||||
// released.
|
||||
//
|
||||
// Input:
|
||||
// interface: handle on the effect interface to be released.
|
||||
//
|
||||
// Output:
|
||||
// returned value: 0 successful operation.
|
||||
// -ENODEV library failed to initialize
|
||||
// -EINVAL invalid interface handle
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
typedef int32_t (*effect_ReleaseEffect_t)(effect_interface_t interface);
|
||||
|
||||
|
||||
#if __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
|
||||
#endif /*ANDROID_EFFECTAPI_H_*/
|
|
@ -0,0 +1,184 @@
|
|||
/*
|
||||
* Copyright (C) 2007 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef ANDROID_IAUDIOFLINGER_H
|
||||
#define ANDROID_IAUDIOFLINGER_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <utils/RefBase.h>
|
||||
#include <utils/Errors.h>
|
||||
#include <binder/IInterface.h>
|
||||
#include "IAudioTrack.h"
|
||||
#include "IAudioRecord.h"
|
||||
#include "IAudioFlingerClient.h"
|
||||
#include "EffectApi.h"
|
||||
#include "IEffect.h"
|
||||
#include "IEffectClient.h"
|
||||
#include <utils/String8.h>
|
||||
|
||||
namespace android {
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
class IAudioFlinger : public IInterface
|
||||
{
|
||||
public:
|
||||
DECLARE_META_INTERFACE(AudioFlinger);
|
||||
|
||||
/* create an audio track and registers it with AudioFlinger.
|
||||
* return null if the track cannot be created.
|
||||
*/
|
||||
virtual sp<IAudioTrack> createTrack(
|
||||
pid_t pid,
|
||||
int streamType,
|
||||
uint32_t sampleRate,
|
||||
int format,
|
||||
int channelCount,
|
||||
int frameCount,
|
||||
uint32_t flags,
|
||||
const sp<IMemory>& sharedBuffer,
|
||||
int output,
|
||||
int *sessionId,
|
||||
status_t *status) = 0;
|
||||
|
||||
virtual sp<IAudioRecord> openRecord(
|
||||
pid_t pid,
|
||||
int input,
|
||||
uint32_t sampleRate,
|
||||
int format,
|
||||
int channelCount,
|
||||
int frameCount,
|
||||
uint32_t flags,
|
||||
int *sessionId,
|
||||
status_t *status) = 0;
|
||||
|
||||
/* query the audio hardware state. This state never changes,
|
||||
* and therefore can be cached.
|
||||
*/
|
||||
virtual uint32_t sampleRate(int output) const = 0;
|
||||
virtual int channelCount(int output) const = 0;
|
||||
virtual int format(int output) const = 0;
|
||||
virtual size_t frameCount(int output) const = 0;
|
||||
virtual uint32_t latency(int output) const = 0;
|
||||
|
||||
/* set/get the audio hardware state. This will probably be used by
|
||||
* the preference panel, mostly.
|
||||
*/
|
||||
virtual status_t setMasterVolume(float value) = 0;
|
||||
virtual status_t setMasterMute(bool muted) = 0;
|
||||
|
||||
virtual float masterVolume() const = 0;
|
||||
virtual bool masterMute() const = 0;
|
||||
|
||||
/* set/get stream type state. This will probably be used by
|
||||
* the preference panel, mostly.
|
||||
*/
|
||||
virtual status_t setStreamVolume(int stream, float value, int output) = 0;
|
||||
virtual status_t setStreamMute(int stream, bool muted) = 0;
|
||||
|
||||
virtual float streamVolume(int stream, int output) const = 0;
|
||||
virtual bool streamMute(int stream) const = 0;
|
||||
|
||||
// set audio mode
|
||||
virtual status_t setMode(int mode) = 0;
|
||||
|
||||
// mic mute/state
|
||||
virtual status_t setMicMute(bool state) = 0;
|
||||
virtual bool getMicMute() const = 0;
|
||||
|
||||
// is any track active on this stream?
|
||||
virtual bool isStreamActive(int stream) const = 0;
|
||||
|
||||
virtual status_t setParameters(int ioHandle, const String8& keyValuePairs) = 0;
|
||||
virtual String8 getParameters(int ioHandle, const String8& keys) = 0;
|
||||
|
||||
// register a current process for audio output change notifications
|
||||
virtual void registerClient(const sp<IAudioFlingerClient>& client) = 0;
|
||||
|
||||
// retrieve the audio recording buffer size
|
||||
virtual size_t getInputBufferSize(uint32_t sampleRate, int format, int channelCount) = 0;
|
||||
|
||||
virtual int openOutput(uint32_t *pDevices,
|
||||
uint32_t *pSamplingRate,
|
||||
uint32_t *pFormat,
|
||||
uint32_t *pChannels,
|
||||
uint32_t *pLatencyMs,
|
||||
uint32_t flags) = 0;
|
||||
virtual int openDuplicateOutput(int output1, int output2) = 0;
|
||||
virtual status_t closeOutput(int output) = 0;
|
||||
virtual status_t suspendOutput(int output) = 0;
|
||||
virtual status_t restoreOutput(int output) = 0;
|
||||
|
||||
virtual int openInput(uint32_t *pDevices,
|
||||
uint32_t *pSamplingRate,
|
||||
uint32_t *pFormat,
|
||||
uint32_t *pChannels,
|
||||
uint32_t acoustics) = 0;
|
||||
virtual status_t closeInput(int input) = 0;
|
||||
|
||||
virtual status_t setStreamOutput(uint32_t stream, int output) = 0;
|
||||
|
||||
virtual status_t setVoiceVolume(float volume) = 0;
|
||||
|
||||
virtual status_t getRenderPosition(uint32_t *halFrames, uint32_t *dspFrames, int output) = 0;
|
||||
|
||||
virtual unsigned int getInputFramesLost(int ioHandle) = 0;
|
||||
|
||||
virtual int newAudioSessionId() = 0;
|
||||
|
||||
virtual status_t loadEffectLibrary(const char *libPath, int *handle) = 0;
|
||||
|
||||
virtual status_t unloadEffectLibrary(int handle) = 0;
|
||||
|
||||
virtual status_t queryNumberEffects(uint32_t *numEffects) = 0;
|
||||
|
||||
virtual status_t queryEffect(uint32_t index, effect_descriptor_t *pDescriptor) = 0;
|
||||
|
||||
virtual status_t getEffectDescriptor(effect_uuid_t *pEffectUUID, effect_descriptor_t *pDescriptor) = 0;
|
||||
|
||||
virtual sp<IEffect> createEffect(pid_t pid,
|
||||
effect_descriptor_t *pDesc,
|
||||
const sp<IEffectClient>& client,
|
||||
int32_t priority,
|
||||
int output,
|
||||
int sessionId,
|
||||
status_t *status,
|
||||
int *id,
|
||||
int *enabled) = 0;
|
||||
|
||||
virtual status_t moveEffects(int session, int srcOutput, int dstOutput) = 0;
|
||||
};
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
class BnAudioFlinger : public BnInterface<IAudioFlinger>
|
||||
{
|
||||
public:
|
||||
virtual status_t onTransact( uint32_t code,
|
||||
const Parcel& data,
|
||||
Parcel* reply,
|
||||
uint32_t flags = 0);
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
}; // namespace android
|
||||
|
||||
#endif // ANDROID_IAUDIOFLINGER_H
|
|
@ -0,0 +1,55 @@
|
|||
/*
|
||||
* Copyright (C) 2009 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef ANDROID_IAUDIOFLINGERCLIENT_H
|
||||
#define ANDROID_IAUDIOFLINGERCLIENT_H
|
||||
|
||||
|
||||
#include <utils/RefBase.h>
|
||||
#include <binder/IInterface.h>
|
||||
#include <utils/KeyedVector.h>
|
||||
|
||||
namespace android {
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
class IAudioFlingerClient : public IInterface
|
||||
{
|
||||
public:
|
||||
DECLARE_META_INTERFACE(AudioFlingerClient);
|
||||
|
||||
// Notifies a change of audio input/output configuration.
|
||||
virtual void ioConfigChanged(int event, int ioHandle, void *param2) = 0;
|
||||
|
||||
};
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
class BnAudioFlingerClient : public BnInterface<IAudioFlingerClient>
|
||||
{
|
||||
public:
|
||||
virtual status_t onTransact( uint32_t code,
|
||||
const Parcel& data,
|
||||
Parcel* reply,
|
||||
uint32_t flags = 0);
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
}; // namespace android
|
||||
|
||||
#endif // ANDROID_IAUDIOFLINGERCLIENT_H
|
|
@ -0,0 +1,68 @@
|
|||
/*
|
||||
* Copyright (C) 2007 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef IAUDIORECORD_H_
|
||||
#define IAUDIORECORD_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <utils/RefBase.h>
|
||||
#include <utils/Errors.h>
|
||||
#include <binder/IInterface.h>
|
||||
#include <binder/IMemory.h>
|
||||
|
||||
|
||||
namespace android {
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
class IAudioRecord : public IInterface
|
||||
{
|
||||
public:
|
||||
DECLARE_META_INTERFACE(AudioRecord);
|
||||
|
||||
/* After it's created the track is not active. Call start() to
|
||||
* make it active. If set, the callback will start being called.
|
||||
*/
|
||||
virtual status_t start() = 0;
|
||||
|
||||
/* Stop a track. If set, the callback will cease being called and
|
||||
* obtainBuffer will return an error. Buffers that are already released
|
||||
* will be processed, unless flush() is called.
|
||||
*/
|
||||
virtual void stop() = 0;
|
||||
|
||||
/* get this tracks control block */
|
||||
virtual sp<IMemory> getCblk() const = 0;
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
class BnAudioRecord : public BnInterface<IAudioRecord>
|
||||
{
|
||||
public:
|
||||
virtual status_t onTransact( uint32_t code,
|
||||
const Parcel& data,
|
||||
Parcel* reply,
|
||||
uint32_t flags = 0);
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
}; // namespace android
|
||||
|
||||
#endif /*IAUDIORECORD_H_*/
|
|
@ -0,0 +1,89 @@
|
|||
/*
|
||||
* Copyright (C) 2007 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef ANDROID_IAUDIOTRACK_H
|
||||
#define ANDROID_IAUDIOTRACK_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <utils/RefBase.h>
|
||||
#include <utils/Errors.h>
|
||||
#include <binder/IInterface.h>
|
||||
#include <binder/IMemory.h>
|
||||
|
||||
|
||||
namespace android {
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
class IAudioTrack : public IInterface
|
||||
{
|
||||
public:
|
||||
DECLARE_META_INTERFACE(AudioTrack);
|
||||
|
||||
/* After it's created the track is not active. Call start() to
|
||||
* make it active. If set, the callback will start being called.
|
||||
*/
|
||||
virtual status_t start() = 0;
|
||||
|
||||
/* Stop a track. If set, the callback will cease being called and
|
||||
* obtainBuffer will return an error. Buffers that are already released
|
||||
* will be processed, unless flush() is called.
|
||||
*/
|
||||
virtual void stop() = 0;
|
||||
|
||||
/* flush a stopped track. All pending buffers are discarded.
|
||||
* This function has no effect if the track is not stoped.
|
||||
*/
|
||||
virtual void flush() = 0;
|
||||
|
||||
/* mute or unmutes this track.
|
||||
* While mutted, the callback, if set, is still called.
|
||||
*/
|
||||
virtual void mute(bool) = 0;
|
||||
|
||||
/* Pause a track. If set, the callback will cease being called and
|
||||
* obtainBuffer will return an error. Buffers that are already released
|
||||
* will be processed, unless flush() is called.
|
||||
*/
|
||||
virtual void pause() = 0;
|
||||
|
||||
/* Attach track auxiliary output to specified effect. Use effectId = 0
|
||||
* to detach track from effect.
|
||||
*/
|
||||
virtual status_t attachAuxEffect(int effectId) = 0;
|
||||
|
||||
/* get this tracks control block */
|
||||
virtual sp<IMemory> getCblk() const = 0;
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
class BnAudioTrack : public BnInterface<IAudioTrack>
|
||||
{
|
||||
public:
|
||||
virtual status_t onTransact( uint32_t code,
|
||||
const Parcel& data,
|
||||
Parcel* reply,
|
||||
uint32_t flags = 0);
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
}; // namespace android
|
||||
|
||||
#endif // ANDROID_IAUDIOTRACK_H
|
|
@ -0,0 +1,60 @@
|
|||
/*
|
||||
* Copyright (C) 2010 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef ANDROID_IEFFECT_H
|
||||
#define ANDROID_IEFFECT_H
|
||||
|
||||
#include <utils/RefBase.h>
|
||||
#include <binder/IInterface.h>
|
||||
#include <binder/Parcel.h>
|
||||
#include <binder/IMemory.h>
|
||||
|
||||
namespace android {
|
||||
|
||||
class IEffect: public IInterface
|
||||
{
|
||||
public:
|
||||
DECLARE_META_INTERFACE(Effect);
|
||||
|
||||
virtual status_t enable() = 0;
|
||||
|
||||
virtual status_t disable() = 0;
|
||||
|
||||
virtual status_t command(uint32_t cmdCode,
|
||||
uint32_t cmdSize,
|
||||
void *pCmdData,
|
||||
uint32_t *pReplySize,
|
||||
void *pReplyData) = 0;
|
||||
|
||||
virtual void disconnect() = 0;
|
||||
|
||||
virtual sp<IMemory> getCblk() const = 0;
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
class BnEffect: public BnInterface<IEffect>
|
||||
{
|
||||
public:
|
||||
virtual status_t onTransact( uint32_t code,
|
||||
const Parcel& data,
|
||||
Parcel* reply,
|
||||
uint32_t flags = 0);
|
||||
};
|
||||
|
||||
}; // namespace android
|
||||
|
||||
#endif // ANDROID_IEFFECT_H
|
|
@ -0,0 +1,54 @@
|
|||
/*
|
||||
* Copyright (C) 2010 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef ANDROID_IEFFECTCLIENT_H
|
||||
#define ANDROID_IEFFECTCLIENT_H
|
||||
|
||||
#include <utils/RefBase.h>
|
||||
#include <binder/IInterface.h>
|
||||
#include <binder/Parcel.h>
|
||||
#include <binder/IMemory.h>
|
||||
|
||||
namespace android {
|
||||
|
||||
class IEffectClient: public IInterface
|
||||
{
|
||||
public:
|
||||
DECLARE_META_INTERFACE(EffectClient);
|
||||
|
||||
virtual void controlStatusChanged(bool controlGranted) = 0;
|
||||
virtual void enableStatusChanged(bool enabled) = 0;
|
||||
virtual void commandExecuted(uint32_t cmdCode,
|
||||
uint32_t cmdSize,
|
||||
void *pCmdData,
|
||||
uint32_t replySize,
|
||||
void *pReplyData) = 0;
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
class BnEffectClient: public BnInterface<IEffectClient>
|
||||
{
|
||||
public:
|
||||
virtual status_t onTransact( uint32_t code,
|
||||
const Parcel& data,
|
||||
Parcel* reply,
|
||||
uint32_t flags = 0);
|
||||
};
|
||||
|
||||
}; // namespace android
|
||||
|
||||
#endif // ANDROID_IEFFECTCLIENT_H
|
|
@ -40,16 +40,14 @@ extern "C" {
|
|||
#include "sydney_audio.h"
|
||||
}
|
||||
|
||||
#include "gonk/AudioTrack.h"
|
||||
#include "android/log.h"
|
||||
#include "media/AudioTrack.h"
|
||||
|
||||
#ifndef ALOG
|
||||
#if defined(DEBUG) || defined(FORCE_ALOG)
|
||||
#define ALOG(args...) __android_log_print(ANDROID_LOG_INFO, "Gecko - SYDNEY_AUDIO" , ## args)
|
||||
#else
|
||||
#define ALOG(args...)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* Gonk implementation based on sydney_audio_android.c */
|
||||
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
# You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
DEPTH = ../..
|
||||
topsrcdir = @top_srcdir@
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
#define USE_GS2_LIBCAMERA
|
||||
#define CameraHardwareInterface CameraHardwareInterface_SGS2
|
||||
#define HAL_openCameraHardware HAL_openCameraHardware_SGS2
|
||||
#include "camera/CameraHardwareInterface.h"
|
||||
#include "gonk/CameraHardwareInterface.h"
|
||||
#undef CameraHardwareInterface
|
||||
#undef USE_GS2_LIBCAMERA
|
||||
#undef HAL_openCameraHardware
|
||||
|
@ -31,7 +31,7 @@
|
|||
#define USE_MAGURO_LIBCAMERA
|
||||
#define CameraHardwareInterface CameraHardwareInterface_MAGURO
|
||||
#define HAL_openCameraHardware HAL_openCameraHardware_MAGURO
|
||||
#include "camera/CameraHardwareInterface.h"
|
||||
#include "gonk/CameraHardwareInterface.h"
|
||||
#undef CameraHardwareInterface
|
||||
#undef USE_MAGURO_LIBCAMERA
|
||||
#undef HAL_openCameraHardware
|
||||
|
@ -42,7 +42,7 @@
|
|||
#define image_rect_type image_rect_type3
|
||||
#define image_rect_struct image_rect_struct3
|
||||
#define CameraHardwareInterface CameraHardwareInterface_DEFAULT
|
||||
#include "camera/CameraHardwareInterface.h"
|
||||
#include "gonk/CameraHardwareInterface.h"
|
||||
#undef CameraHardwareInterface
|
||||
|
||||
using namespace android;
|
||||
|
|
|
@ -0,0 +1,256 @@
|
|||
/*
|
||||
* Copyright (C) 2008 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef ANDROID_HARDWARE_CAMERA_H
|
||||
#define ANDROID_HARDWARE_CAMERA_H
|
||||
|
||||
#include <utils/Timers.h>
|
||||
#include "ICameraClient.h"
|
||||
|
||||
namespace android {
|
||||
|
||||
class ISurface;
|
||||
|
||||
/*
|
||||
* A set of bit masks for specifying how the received preview frames are
|
||||
* handled before the previewCallback() call.
|
||||
*
|
||||
* The least significant 3 bits of an "int" value are used for this purpose:
|
||||
*
|
||||
* ..... 0 0 0
|
||||
* ^ ^ ^
|
||||
* | | |---------> determine whether the callback is enabled or not
|
||||
* | |-----------> determine whether the callback is one-shot or not
|
||||
* |-------------> determine whether the frame is copied out or not
|
||||
*
|
||||
* WARNING:
|
||||
* When a frame is sent directly without copying, it is the frame receiver's
|
||||
* responsiblity to make sure that the frame data won't get corrupted by
|
||||
* subsequent preview frames filled by the camera. This flag is recommended
|
||||
* only when copying out data brings significant performance price and the
|
||||
* handling/processing of the received frame data is always faster than
|
||||
* the preview frame rate so that data corruption won't occur.
|
||||
*
|
||||
* For instance,
|
||||
* 1. 0x00 disables the callback. In this case, copy out and one shot bits
|
||||
* are ignored.
|
||||
* 2. 0x01 enables a callback without copying out the received frames. A
|
||||
* typical use case is the Camcorder application to avoid making costly
|
||||
* frame copies.
|
||||
* 3. 0x05 is enabling a callback with frame copied out repeatedly. A typical
|
||||
* use case is the Camera application.
|
||||
* 4. 0x07 is enabling a callback with frame copied out only once. A typical use
|
||||
* case is the Barcode scanner application.
|
||||
*/
|
||||
#define FRAME_CALLBACK_FLAG_ENABLE_MASK 0x01
|
||||
#define FRAME_CALLBACK_FLAG_ONE_SHOT_MASK 0x02
|
||||
#define FRAME_CALLBACK_FLAG_COPY_OUT_MASK 0x04
|
||||
|
||||
// Typical use cases
|
||||
#define FRAME_CALLBACK_FLAG_NOOP 0x00
|
||||
#define FRAME_CALLBACK_FLAG_CAMCORDER 0x01
|
||||
#define FRAME_CALLBACK_FLAG_CAMERA 0x05
|
||||
#define FRAME_CALLBACK_FLAG_BARCODE_SCANNER 0x07
|
||||
|
||||
// msgType in notifyCallback and dataCallback functions
|
||||
enum {
|
||||
CAMERA_MSG_ERROR = 0x001,
|
||||
CAMERA_MSG_SHUTTER = 0x002,
|
||||
CAMERA_MSG_FOCUS = 0x004,
|
||||
CAMERA_MSG_ZOOM = 0x008,
|
||||
CAMERA_MSG_PREVIEW_FRAME = 0x010,
|
||||
CAMERA_MSG_VIDEO_FRAME = 0x020,
|
||||
CAMERA_MSG_POSTVIEW_FRAME = 0x040,
|
||||
CAMERA_MSG_RAW_IMAGE = 0x080,
|
||||
CAMERA_MSG_COMPRESSED_IMAGE = 0x100,
|
||||
CAMERA_MSG_ALL_MSGS = 0x1FF
|
||||
};
|
||||
|
||||
// cmdType in sendCommand functions
|
||||
enum {
|
||||
CAMERA_CMD_START_SMOOTH_ZOOM = 1,
|
||||
CAMERA_CMD_STOP_SMOOTH_ZOOM = 2,
|
||||
// Set the clockwise rotation of preview display (setPreviewDisplay) in
|
||||
// degrees. This affects the preview frames and the picture displayed after
|
||||
// snapshot. This method is useful for portrait mode applications. Note that
|
||||
// preview display of front-facing cameras is flipped horizontally before
|
||||
// the rotation, that is, the image is reflected along the central vertical
|
||||
// axis of the camera sensor. So the users can see themselves as looking
|
||||
// into a mirror.
|
||||
//
|
||||
// This does not affect the order of byte array of CAMERA_MSG_PREVIEW_FRAME,
|
||||
// CAMERA_MSG_VIDEO_FRAME, CAMERA_MSG_POSTVIEW_FRAME, CAMERA_MSG_RAW_IMAGE,
|
||||
// or CAMERA_MSG_COMPRESSED_IMAGE. This is not allowed to be set during
|
||||
// preview.
|
||||
CAMERA_CMD_SET_DISPLAY_ORIENTATION = 3,
|
||||
};
|
||||
|
||||
// camera fatal errors
|
||||
enum {
|
||||
CAMERA_ERROR_UKNOWN = 1,
|
||||
CAMERA_ERROR_SERVER_DIED = 100
|
||||
};
|
||||
|
||||
enum {
|
||||
CAMERA_FACING_BACK = 0, /* The facing of the camera is opposite to that of the screen. */
|
||||
CAMERA_FACING_FRONT = 1 /* The facing of the camera is the same as that of the screen. */
|
||||
};
|
||||
|
||||
struct CameraInfo {
|
||||
|
||||
/**
|
||||
* The direction that the camera faces to. It should be
|
||||
* CAMERA_FACING_BACK or CAMERA_FACING_FRONT.
|
||||
*/
|
||||
int facing;
|
||||
|
||||
/**
|
||||
* The orientation of the camera image. The value is the angle that the
|
||||
* camera image needs to be rotated clockwise so it shows correctly on
|
||||
* the display in its natural orientation. It should be 0, 90, 180, or 270.
|
||||
*
|
||||
* For example, suppose a device has a naturally tall screen. The
|
||||
* back-facing camera sensor is mounted in landscape. You are looking at
|
||||
* the screen. If the top side of the camera sensor is aligned with the
|
||||
* right edge of the screen in natural orientation, the value should be
|
||||
* 90. If the top side of a front-facing camera sensor is aligned with
|
||||
* the right of the screen, the value should be 270.
|
||||
*/
|
||||
int orientation;
|
||||
};
|
||||
|
||||
class ICameraService;
|
||||
class ICamera;
|
||||
class Surface;
|
||||
class Mutex;
|
||||
class String8;
|
||||
|
||||
// ref-counted object for callbacks
|
||||
class CameraListener: virtual public RefBase
|
||||
{
|
||||
public:
|
||||
virtual void notify(int32_t msgType, int32_t ext1, int32_t ext2) = 0;
|
||||
virtual void postData(int32_t msgType, const sp<IMemory>& dataPtr) = 0;
|
||||
virtual void postDataTimestamp(nsecs_t timestamp, int32_t msgType, const sp<IMemory>& dataPtr) = 0;
|
||||
};
|
||||
|
||||
class Camera : public BnCameraClient, public IBinder::DeathRecipient
|
||||
{
|
||||
public:
|
||||
// construct a camera client from an existing remote
|
||||
static sp<Camera> create(const sp<ICamera>& camera);
|
||||
static int32_t getNumberOfCameras();
|
||||
static status_t getCameraInfo(int cameraId,
|
||||
struct CameraInfo* cameraInfo);
|
||||
static sp<Camera> connect(int cameraId);
|
||||
~Camera();
|
||||
void init();
|
||||
|
||||
status_t reconnect();
|
||||
void disconnect();
|
||||
status_t lock();
|
||||
status_t unlock();
|
||||
|
||||
status_t getStatus() { return mStatus; }
|
||||
|
||||
// pass the buffered ISurface to the camera service
|
||||
status_t setPreviewDisplay(const sp<Surface>& surface);
|
||||
status_t setPreviewDisplay(const sp<ISurface>& surface);
|
||||
|
||||
// start preview mode, must call setPreviewDisplay first
|
||||
status_t startPreview();
|
||||
|
||||
// stop preview mode
|
||||
void stopPreview();
|
||||
|
||||
// get preview state
|
||||
bool previewEnabled();
|
||||
|
||||
// start recording mode, must call setPreviewDisplay first
|
||||
status_t startRecording();
|
||||
|
||||
// stop recording mode
|
||||
void stopRecording();
|
||||
|
||||
// get recording state
|
||||
bool recordingEnabled();
|
||||
|
||||
// release a recording frame
|
||||
void releaseRecordingFrame(const sp<IMemory>& mem);
|
||||
|
||||
// autoFocus - status returned from callback
|
||||
status_t autoFocus();
|
||||
|
||||
// cancel auto focus
|
||||
status_t cancelAutoFocus();
|
||||
|
||||
// take a picture - picture returned from callback
|
||||
status_t takePicture();
|
||||
|
||||
// set preview/capture parameters - key/value pairs
|
||||
status_t setParameters(const String8& params);
|
||||
|
||||
// get preview/capture parameters - key/value pairs
|
||||
String8 getParameters() const;
|
||||
|
||||
// send command to camera driver
|
||||
status_t sendCommand(int32_t cmd, int32_t arg1, int32_t arg2);
|
||||
|
||||
void setListener(const sp<CameraListener>& listener);
|
||||
void setPreviewCallbackFlags(int preview_callback_flag);
|
||||
|
||||
// ICameraClient interface
|
||||
virtual void notifyCallback(int32_t msgType, int32_t ext, int32_t ext2);
|
||||
virtual void dataCallback(int32_t msgType, const sp<IMemory>& dataPtr);
|
||||
virtual void dataCallbackTimestamp(nsecs_t timestamp, int32_t msgType, const sp<IMemory>& dataPtr);
|
||||
|
||||
sp<ICamera> remote();
|
||||
|
||||
private:
|
||||
Camera();
|
||||
Camera(const Camera&);
|
||||
Camera& operator=(const Camera);
|
||||
virtual void binderDied(const wp<IBinder>& who);
|
||||
|
||||
class DeathNotifier: public IBinder::DeathRecipient
|
||||
{
|
||||
public:
|
||||
DeathNotifier() {
|
||||
}
|
||||
|
||||
virtual void binderDied(const wp<IBinder>& who);
|
||||
};
|
||||
|
||||
static sp<DeathNotifier> mDeathNotifier;
|
||||
|
||||
// helper function to obtain camera service handle
|
||||
static const sp<ICameraService>& getCameraService();
|
||||
|
||||
sp<ICamera> mCamera;
|
||||
status_t mStatus;
|
||||
|
||||
sp<CameraListener> mListener;
|
||||
|
||||
friend class DeathNotifier;
|
||||
|
||||
static Mutex mLock;
|
||||
static sp<ICameraService> mCameraService;
|
||||
|
||||
};
|
||||
|
||||
}; // namespace android
|
||||
|
||||
#endif
|
|
@ -0,0 +1,267 @@
|
|||
/*
|
||||
* Copyright (C) 2008 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef ANDROID_HARDWARE_CAMERA_HARDWARE_INTERFACE_H
|
||||
#define ANDROID_HARDWARE_CAMERA_HARDWARE_INTERFACE_H
|
||||
|
||||
#include <binder/IMemory.h>
|
||||
#include <utils/RefBase.h>
|
||||
#include <surfaceflinger/ISurface.h>
|
||||
#include "Camera.h"
|
||||
#include "CameraParameters.h"
|
||||
|
||||
namespace android {
|
||||
|
||||
class Overlay;
|
||||
|
||||
/**
|
||||
* The size of image for display.
|
||||
*/
|
||||
typedef struct image_rect_struct
|
||||
{
|
||||
uint32_t width; /* Image width */
|
||||
uint32_t height; /* Image height */
|
||||
} image_rect_type;
|
||||
|
||||
|
||||
typedef void (*notify_callback)(int32_t msgType,
|
||||
int32_t ext1,
|
||||
int32_t ext2,
|
||||
void* user);
|
||||
|
||||
typedef void (*data_callback)(int32_t msgType,
|
||||
const sp<IMemory>& dataPtr,
|
||||
void* user);
|
||||
|
||||
typedef void (*data_callback_timestamp)(nsecs_t timestamp,
|
||||
int32_t msgType,
|
||||
const sp<IMemory>& dataPtr,
|
||||
void* user);
|
||||
|
||||
/**
|
||||
* CameraHardwareInterface.h defines the interface to the
|
||||
* camera hardware abstraction layer, used for setting and getting
|
||||
* parameters, live previewing, and taking pictures.
|
||||
*
|
||||
* It is a referenced counted interface with RefBase as its base class.
|
||||
* CameraService calls openCameraHardware() to retrieve a strong pointer to the
|
||||
* instance of this interface and may be called multiple times. The
|
||||
* following steps describe a typical sequence:
|
||||
*
|
||||
* -# After CameraService calls openCameraHardware(), getParameters() and
|
||||
* setParameters() are used to initialize the camera instance.
|
||||
* CameraService calls getPreviewHeap() to establish access to the
|
||||
* preview heap so it can be registered with SurfaceFlinger for
|
||||
* efficient display updating while in preview mode.
|
||||
* -# startPreview() is called. The camera instance then periodically
|
||||
* sends the message CAMERA_MSG_PREVIEW_FRAME (if enabled) each time
|
||||
* a new preview frame is available. If data callback code needs to use
|
||||
* this memory after returning, it must copy the data.
|
||||
*
|
||||
* Prior to taking a picture, CameraService calls autofocus(). When auto
|
||||
* focusing has completed, the camera instance sends a CAMERA_MSG_FOCUS notification,
|
||||
* which informs the application whether focusing was successful. The camera instance
|
||||
* only sends this message once and it is up to the application to call autoFocus()
|
||||
* again if refocusing is desired.
|
||||
*
|
||||
* CameraService calls takePicture() to request the camera instance take a
|
||||
* picture. At this point, if a shutter, postview, raw, and/or compressed callback
|
||||
* is desired, the corresponding message must be enabled. As with CAMERA_MSG_PREVIEW_FRAME,
|
||||
* any memory provided in a data callback must be copied if it's needed after returning.
|
||||
*/
|
||||
class CameraHardwareInterface : public virtual RefBase {
|
||||
public:
|
||||
virtual ~CameraHardwareInterface() { }
|
||||
|
||||
/** Return the IMemoryHeap for the preview image heap */
|
||||
virtual sp<IMemoryHeap> getPreviewHeap() const = 0;
|
||||
|
||||
/** Return the IMemoryHeap for the raw image heap */
|
||||
virtual sp<IMemoryHeap> getRawHeap() const = 0;
|
||||
|
||||
/** Set the notification and data callbacks */
|
||||
virtual void setCallbacks(notify_callback notify_cb,
|
||||
data_callback data_cb,
|
||||
data_callback_timestamp data_cb_timestamp,
|
||||
void* user) = 0;
|
||||
|
||||
/**
|
||||
* The following three functions all take a msgtype,
|
||||
* which is a bitmask of the messages defined in
|
||||
* include/ui/Camera.h
|
||||
*/
|
||||
|
||||
/**
|
||||
* Enable a message, or set of messages.
|
||||
*/
|
||||
virtual void enableMsgType(int32_t msgType) = 0;
|
||||
|
||||
/**
|
||||
* Disable a message, or a set of messages.
|
||||
*/
|
||||
virtual void disableMsgType(int32_t msgType) = 0;
|
||||
|
||||
/**
|
||||
* Query whether a message, or a set of messages, is enabled.
|
||||
* Note that this is operates as an AND, if any of the messages
|
||||
* queried are off, this will return false.
|
||||
*/
|
||||
virtual bool msgTypeEnabled(int32_t msgType) = 0;
|
||||
|
||||
/**
|
||||
* Start preview mode.
|
||||
*/
|
||||
virtual status_t startPreview() = 0;
|
||||
|
||||
#ifdef USE_MAGURO_LIBCAMERA
|
||||
/**
|
||||
* Query the recording buffer information from HAL.
|
||||
* This is needed because the opencore expects the buffer
|
||||
* information before starting the recording.
|
||||
*/
|
||||
virtual status_t getBufferInfo(sp<IMemory>& Frame, size_t *alignedSize) = 0;
|
||||
|
||||
/**
|
||||
* Encode the YUV data.
|
||||
*/
|
||||
virtual void encodeData() = 0;
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Only used if overlays are used for camera preview.
|
||||
*/
|
||||
virtual bool useOverlay() {return false;}
|
||||
virtual status_t setOverlay(const sp<Overlay> &overlay) {return BAD_VALUE;}
|
||||
|
||||
#ifdef USE_GS2_LIBCAMERA
|
||||
/**
|
||||
* XXX Something in the binary blob but I don't know what it is to do.
|
||||
*/
|
||||
virtual void something() {}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Stop a previously started preview.
|
||||
*/
|
||||
virtual void stopPreview() = 0;
|
||||
|
||||
/**
|
||||
* Returns true if preview is enabled.
|
||||
*/
|
||||
virtual bool previewEnabled() = 0;
|
||||
|
||||
/**
|
||||
* Start record mode. When a record image is available a CAMERA_MSG_VIDEO_FRAME
|
||||
* message is sent with the corresponding frame. Every record frame must be released
|
||||
* by calling releaseRecordingFrame().
|
||||
*/
|
||||
virtual status_t startRecording() = 0;
|
||||
|
||||
/**
|
||||
* Stop a previously started recording.
|
||||
*/
|
||||
virtual void stopRecording() = 0;
|
||||
|
||||
/**
|
||||
* Returns true if recording is enabled.
|
||||
*/
|
||||
virtual bool recordingEnabled() = 0;
|
||||
|
||||
/**
|
||||
* Release a record frame previously returned by CAMERA_MSG_VIDEO_FRAME.
|
||||
*/
|
||||
virtual void releaseRecordingFrame(const sp<IMemory>& mem) = 0;
|
||||
|
||||
/**
|
||||
* Start auto focus, the notification callback routine is called
|
||||
* with CAMERA_MSG_FOCUS once when focusing is complete. autoFocus()
|
||||
* will be called again if another auto focus is needed.
|
||||
*/
|
||||
virtual status_t autoFocus() = 0;
|
||||
|
||||
/**
|
||||
* Cancels auto-focus function. If the auto-focus is still in progress,
|
||||
* this function will cancel it. Whether the auto-focus is in progress
|
||||
* or not, this function will return the focus position to the default.
|
||||
* If the camera does not support auto-focus, this is a no-op.
|
||||
*/
|
||||
virtual status_t cancelAutoFocus() = 0;
|
||||
|
||||
/**
|
||||
* Take a picture.
|
||||
*/
|
||||
virtual status_t takePicture() = 0;
|
||||
|
||||
/**
|
||||
* Cancel a picture that was started with takePicture. Calling this
|
||||
* method when no picture is being taken is a no-op.
|
||||
*/
|
||||
virtual status_t cancelPicture() = 0;
|
||||
|
||||
/**
|
||||
* Set the camera parameters. This returns BAD_VALUE if any parameter is
|
||||
* invalid or not supported. */
|
||||
virtual status_t setParameters(const CameraParameters& params) = 0;
|
||||
|
||||
/** Return the camera parameters. */
|
||||
virtual CameraParameters getParameters() const = 0;
|
||||
|
||||
/**
|
||||
* Send command to camera driver.
|
||||
*/
|
||||
virtual status_t sendCommand(int32_t cmd, int32_t arg1, int32_t arg2) = 0;
|
||||
|
||||
/**
|
||||
* Release the hardware resources owned by this object. Note that this is
|
||||
* *not* done in the destructor.
|
||||
*/
|
||||
virtual void release() = 0;
|
||||
|
||||
/**
|
||||
* Dump state of the camera hardware
|
||||
*/
|
||||
virtual status_t dump(int fd, const Vector<String16>& args) const = 0;
|
||||
|
||||
#ifdef USE_MAGURO_LIBCAMERA
|
||||
/**
|
||||
* Take a LiveSnapshot - Picture while recording
|
||||
*/
|
||||
virtual status_t takeLiveSnapshot() = 0;
|
||||
#endif
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* The functions need to be provided by the camera HAL.
|
||||
*
|
||||
* If getNumberOfCameras() returns N, the valid cameraId for getCameraInfo()
|
||||
* and openCameraHardware() is 0 to N-1.
|
||||
*/
|
||||
extern "C" int HAL_getNumberOfCameras();
|
||||
extern "C" void HAL_getCameraInfo(int cameraId, struct CameraInfo* cameraInfo);
|
||||
#ifdef USE_MAGURO_LIBCAMERA
|
||||
/* HAL should return NULL if it fails to open camera hardware. */
|
||||
extern "C" sp<CameraHardwareInterface> HAL_openCameraHardware(int cameraId, int mode);
|
||||
/* Returns whether the camera is in 3D mode or not */
|
||||
extern "C" int HAL_isIn3DMode();
|
||||
#else
|
||||
/* HAL should return NULL if it fails to open camera hardware. */
|
||||
extern "C" sp<CameraHardwareInterface> HAL_openCameraHardware(int cameraId);
|
||||
#endif
|
||||
|
||||
}; // namespace android
|
||||
|
||||
#endif
|
|
@ -0,0 +1,405 @@
|
|||
/*
|
||||
* Copyright (C) 2008 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef ANDROID_HARDWARE_CAMERA_PARAMETERS_H
|
||||
#define ANDROID_HARDWARE_CAMERA_PARAMETERS_H
|
||||
|
||||
#include <utils/KeyedVector.h>
|
||||
#include <utils/String8.h>
|
||||
|
||||
namespace android {
|
||||
|
||||
struct Size {
|
||||
int width;
|
||||
int height;
|
||||
|
||||
Size() {
|
||||
width = 0;
|
||||
height = 0;
|
||||
}
|
||||
|
||||
Size(int w, int h) {
|
||||
width = w;
|
||||
height = h;
|
||||
}
|
||||
};
|
||||
|
||||
class CameraParameters
|
||||
{
|
||||
public:
|
||||
CameraParameters();
|
||||
CameraParameters(const String8 ¶ms) { unflatten(params); }
|
||||
~CameraParameters();
|
||||
|
||||
String8 flatten() const;
|
||||
void unflatten(const String8 ¶ms);
|
||||
|
||||
void set(const char *key, const char *value);
|
||||
void set(const char *key, int value);
|
||||
void setFloat(const char *key, float value);
|
||||
const char *get(const char *key) const;
|
||||
int getInt(const char *key) const;
|
||||
float getFloat(const char *key) const;
|
||||
|
||||
void remove(const char *key);
|
||||
|
||||
void setPreviewSize(int width, int height);
|
||||
void getPreviewSize(int *width, int *height) const;
|
||||
void getSupportedPreviewSizes(Vector<Size> &sizes) const;
|
||||
void setPreviewFrameRate(int fps);
|
||||
int getPreviewFrameRate() const;
|
||||
void getPreviewFpsRange(int *min_fps, int *max_fps) const;
|
||||
void setPreviewFormat(const char *format);
|
||||
const char *getPreviewFormat() const;
|
||||
void setPictureSize(int width, int height);
|
||||
void getPictureSize(int *width, int *height) const;
|
||||
void getSupportedPictureSizes(Vector<Size> &sizes) const;
|
||||
void setPictureFormat(const char *format);
|
||||
const char *getPictureFormat() const;
|
||||
|
||||
void dump() const;
|
||||
status_t dump(int fd, const Vector<String16>& args) const;
|
||||
|
||||
// Parameter keys to communicate between camera application and driver.
|
||||
// The access (read/write, read only, or write only) is viewed from the
|
||||
// perspective of applications, not driver.
|
||||
|
||||
// Preview frame size in pixels (width x height).
|
||||
// Example value: "480x320". Read/Write.
|
||||
static const char KEY_PREVIEW_SIZE[];
|
||||
// Supported preview frame sizes in pixels.
|
||||
// Example value: "800x600,480x320". Read only.
|
||||
static const char KEY_SUPPORTED_PREVIEW_SIZES[];
|
||||
// The current minimum and maximum preview fps. This controls the rate of
|
||||
// preview frames received (CAMERA_MSG_PREVIEW_FRAME). The minimum and
|
||||
// maximum fps must be one of the elements from
|
||||
// KEY_SUPPORTED_PREVIEW_FPS_RANGE parameter.
|
||||
// Example value: "10500,26623"
|
||||
static const char KEY_PREVIEW_FPS_RANGE[];
|
||||
// The supported preview fps (frame-per-second) ranges. Each range contains
|
||||
// a minimum fps and maximum fps. If minimum fps equals to maximum fps, the
|
||||
// camera outputs frames in fixed frame rate. If not, the camera outputs
|
||||
// frames in auto frame rate. The actual frame rate fluctuates between the
|
||||
// minimum and the maximum. The list has at least one element. The list is
|
||||
// sorted from small to large (first by maximum fps and then minimum fps).
|
||||
// Example value: "(10500,26623),(15000,26623),(30000,30000)"
|
||||
static const char KEY_SUPPORTED_PREVIEW_FPS_RANGE[];
|
||||
// The image format for preview frames. See CAMERA_MSG_PREVIEW_FRAME in
|
||||
// frameworks/base/include/camera/Camera.h.
|
||||
// Example value: "yuv420sp" or PIXEL_FORMAT_XXX constants. Read/write.
|
||||
static const char KEY_PREVIEW_FORMAT[];
|
||||
// Supported image formats for preview frames.
|
||||
// Example value: "yuv420sp,yuv422i-yuyv". Read only.
|
||||
static const char KEY_SUPPORTED_PREVIEW_FORMATS[];
|
||||
// Number of preview frames per second. This is the target frame rate. The
|
||||
// actual frame rate depends on the driver.
|
||||
// Example value: "15". Read/write.
|
||||
static const char KEY_PREVIEW_FRAME_RATE[];
|
||||
// Supported number of preview frames per second.
|
||||
// Example value: "24,15,10". Read.
|
||||
static const char KEY_SUPPORTED_PREVIEW_FRAME_RATES[];
|
||||
// The dimensions for captured pictures in pixels (width x height).
|
||||
// Example value: "1024x768". Read/write.
|
||||
static const char KEY_PICTURE_SIZE[];
|
||||
// Supported dimensions for captured pictures in pixels.
|
||||
// Example value: "2048x1536,1024x768". Read only.
|
||||
static const char KEY_SUPPORTED_PICTURE_SIZES[];
|
||||
// The image format for captured pictures. See CAMERA_MSG_COMPRESSED_IMAGE
|
||||
// in frameworks/base/include/camera/Camera.h.
|
||||
// Example value: "jpeg" or PIXEL_FORMAT_XXX constants. Read/write.
|
||||
static const char KEY_PICTURE_FORMAT[];
|
||||
// Supported image formats for captured pictures.
|
||||
// Example value: "jpeg,rgb565". Read only.
|
||||
static const char KEY_SUPPORTED_PICTURE_FORMATS[];
|
||||
// The width (in pixels) of EXIF thumbnail in Jpeg picture.
|
||||
// Example value: "512". Read/write.
|
||||
static const char KEY_JPEG_THUMBNAIL_WIDTH[];
|
||||
// The height (in pixels) of EXIF thumbnail in Jpeg picture.
|
||||
// Example value: "384". Read/write.
|
||||
static const char KEY_JPEG_THUMBNAIL_HEIGHT[];
|
||||
// Supported EXIF thumbnail sizes (width x height). 0x0 means not thumbnail
|
||||
// in EXIF.
|
||||
// Example value: "512x384,320x240,0x0". Read only.
|
||||
static const char KEY_SUPPORTED_JPEG_THUMBNAIL_SIZES[];
|
||||
// The quality of the EXIF thumbnail in Jpeg picture. The range is 1 to 100,
|
||||
// with 100 being the best.
|
||||
// Example value: "90". Read/write.
|
||||
static const char KEY_JPEG_THUMBNAIL_QUALITY[];
|
||||
// Jpeg quality of captured picture. The range is 1 to 100, with 100 being
|
||||
// the best.
|
||||
// Example value: "90". Read/write.
|
||||
static const char KEY_JPEG_QUALITY[];
|
||||
// The rotation angle in degrees relative to the orientation of the camera.
|
||||
// This affects the pictures returned from CAMERA_MSG_COMPRESSED_IMAGE. The
|
||||
// camera driver may set orientation in the EXIF header without rotating the
|
||||
// picture. Or the driver may rotate the picture and the EXIF thumbnail. If
|
||||
// the Jpeg picture is rotated, the orientation in the EXIF header will be
|
||||
// missing or 1 (row #0 is top and column #0 is left side).
|
||||
//
|
||||
// Note that the JPEG pictures of front-facing cameras are not mirrored
|
||||
// as in preview display.
|
||||
//
|
||||
// For example, suppose the natural orientation of the device is portrait.
|
||||
// The device is rotated 270 degrees clockwise, so the device orientation is
|
||||
// 270. Suppose a back-facing camera sensor is mounted in landscape and the
|
||||
// top side of the camera sensor is aligned with the right edge of the
|
||||
// display in natural orientation. So the camera orientation is 90. The
|
||||
// rotation should be set to 0 (270 + 90).
|
||||
//
|
||||
// Example value: "0" or "90" or "180" or "270". Write only.
|
||||
static const char KEY_ROTATION[];
|
||||
// GPS latitude coordinate. GPSLatitude and GPSLatitudeRef will be stored in
|
||||
// JPEG EXIF header.
|
||||
// Example value: "25.032146" or "-33.462809". Write only.
|
||||
static const char KEY_GPS_LATITUDE[];
|
||||
// GPS longitude coordinate. GPSLongitude and GPSLongitudeRef will be stored
|
||||
// in JPEG EXIF header.
|
||||
// Example value: "121.564448" or "-70.660286". Write only.
|
||||
static const char KEY_GPS_LONGITUDE[];
|
||||
// GPS altitude. GPSAltitude and GPSAltitudeRef will be stored in JPEG EXIF
|
||||
// header.
|
||||
// Example value: "21.0" or "-5". Write only.
|
||||
static const char KEY_GPS_ALTITUDE[];
|
||||
// GPS timestamp (UTC in seconds since January 1, 1970). This should be
|
||||
// stored in JPEG EXIF header.
|
||||
// Example value: "1251192757". Write only.
|
||||
static const char KEY_GPS_TIMESTAMP[];
|
||||
// GPS Processing Method
|
||||
// Example value: "GPS" or "NETWORK". Write only.
|
||||
static const char KEY_GPS_PROCESSING_METHOD[];
|
||||
// Current white balance setting.
|
||||
// Example value: "auto" or WHITE_BALANCE_XXX constants. Read/write.
|
||||
static const char KEY_WHITE_BALANCE[];
|
||||
// Supported white balance settings.
|
||||
// Example value: "auto,incandescent,daylight". Read only.
|
||||
static const char KEY_SUPPORTED_WHITE_BALANCE[];
|
||||
// Current color effect setting.
|
||||
// Example value: "none" or EFFECT_XXX constants. Read/write.
|
||||
static const char KEY_EFFECT[];
|
||||
// Supported color effect settings.
|
||||
// Example value: "none,mono,sepia". Read only.
|
||||
static const char KEY_SUPPORTED_EFFECTS[];
|
||||
// Current antibanding setting.
|
||||
// Example value: "auto" or ANTIBANDING_XXX constants. Read/write.
|
||||
static const char KEY_ANTIBANDING[];
|
||||
// Supported antibanding settings.
|
||||
// Example value: "auto,50hz,60hz,off". Read only.
|
||||
static const char KEY_SUPPORTED_ANTIBANDING[];
|
||||
// Current scene mode.
|
||||
// Example value: "auto" or SCENE_MODE_XXX constants. Read/write.
|
||||
static const char KEY_SCENE_MODE[];
|
||||
// Supported scene mode settings.
|
||||
// Example value: "auto,night,fireworks". Read only.
|
||||
static const char KEY_SUPPORTED_SCENE_MODES[];
|
||||
// Current flash mode.
|
||||
// Example value: "auto" or FLASH_MODE_XXX constants. Read/write.
|
||||
static const char KEY_FLASH_MODE[];
|
||||
// Supported flash modes.
|
||||
// Example value: "auto,on,off". Read only.
|
||||
static const char KEY_SUPPORTED_FLASH_MODES[];
|
||||
// Current focus mode. This will not be empty. Applications should call
|
||||
// CameraHardwareInterface.autoFocus to start the focus if focus mode is
|
||||
// FOCUS_MODE_AUTO or FOCUS_MODE_MACRO.
|
||||
// Example value: "auto" or FOCUS_MODE_XXX constants. Read/write.
|
||||
static const char KEY_FOCUS_MODE[];
|
||||
// Supported focus modes.
|
||||
// Example value: "auto,macro,fixed". Read only.
|
||||
static const char KEY_SUPPORTED_FOCUS_MODES[];
|
||||
// Focal length in millimeter.
|
||||
// Example value: "4.31". Read only.
|
||||
static const char KEY_FOCAL_LENGTH[];
|
||||
// Horizontal angle of view in degrees.
|
||||
// Example value: "54.8". Read only.
|
||||
static const char KEY_HORIZONTAL_VIEW_ANGLE[];
|
||||
// Vertical angle of view in degrees.
|
||||
// Example value: "42.5". Read only.
|
||||
static const char KEY_VERTICAL_VIEW_ANGLE[];
|
||||
// Exposure compensation index. 0 means exposure is not adjusted.
|
||||
// Example value: "0" or "5". Read/write.
|
||||
static const char KEY_EXPOSURE_COMPENSATION[];
|
||||
// The maximum exposure compensation index (>=0).
|
||||
// Example value: "6". Read only.
|
||||
static const char KEY_MAX_EXPOSURE_COMPENSATION[];
|
||||
// The minimum exposure compensation index (<=0).
|
||||
// Example value: "-6". Read only.
|
||||
static const char KEY_MIN_EXPOSURE_COMPENSATION[];
|
||||
// The exposure compensation step. Exposure compensation index multiply by
|
||||
// step eqals to EV. Ex: if exposure compensation index is 6 and step is
|
||||
// 0.3333, EV is -2.
|
||||
// Example value: "0.333333333" or "0.5". Read only.
|
||||
static const char KEY_EXPOSURE_COMPENSATION_STEP[];
|
||||
// Current zoom value.
|
||||
// Example value: "0" or "6". Read/write.
|
||||
static const char KEY_ZOOM[];
|
||||
// Maximum zoom value.
|
||||
// Example value: "6". Read only.
|
||||
static const char KEY_MAX_ZOOM[];
|
||||
// The zoom ratios of all zoom values. The zoom ratio is in 1/100
|
||||
// increments. Ex: a zoom of 3.2x is returned as 320. The number of list
|
||||
// elements is KEY_MAX_ZOOM + 1. The first element is always 100. The last
|
||||
// element is the zoom ratio of zoom value KEY_MAX_ZOOM.
|
||||
// Example value: "100,150,200,250,300,350,400". Read only.
|
||||
static const char KEY_ZOOM_RATIOS[];
|
||||
// Whether zoom is supported. Zoom is supported if the value is "true". Zoom
|
||||
// is not supported if the value is not "true" or the key does not exist.
|
||||
// Example value: "true". Read only.
|
||||
static const char KEY_ZOOM_SUPPORTED[];
|
||||
// Whether if smooth zoom is supported. Smooth zoom is supported if the
|
||||
// value is "true". It is not supported if the value is not "true" or the
|
||||
// key does not exist.
|
||||
// See CAMERA_CMD_START_SMOOTH_ZOOM, CAMERA_CMD_STOP_SMOOTH_ZOOM, and
|
||||
// CAMERA_MSG_ZOOM in frameworks/base/include/camera/Camera.h.
|
||||
// Example value: "true". Read only.
|
||||
static const char KEY_SMOOTH_ZOOM_SUPPORTED[];
|
||||
|
||||
// The distances (in meters) from the camera to where an object appears to
|
||||
// be in focus. The object is sharpest at the optimal focus distance. The
|
||||
// depth of field is the far focus distance minus near focus distance.
|
||||
//
|
||||
// Focus distances may change after starting auto focus, canceling auto
|
||||
// focus, or starting the preview. Applications can read this anytime to get
|
||||
// the latest focus distances. If the focus mode is FOCUS_MODE_CONTINUOUS,
|
||||
// focus distances may change from time to time.
|
||||
//
|
||||
// This is intended to estimate the distance between the camera and the
|
||||
// subject. After autofocus, the subject distance may be within near and far
|
||||
// focus distance. However, the precision depends on the camera hardware,
|
||||
// autofocus algorithm, the focus area, and the scene. The error can be
|
||||
// large and it should be only used as a reference.
|
||||
//
|
||||
// Far focus distance > optimal focus distance > near focus distance. If
|
||||
// the far focus distance is infinity, the value should be "Infinity" (case
|
||||
// sensitive). The format is three float values separated by commas. The
|
||||
// first is near focus distance. The second is optimal focus distance. The
|
||||
// third is far focus distance.
|
||||
// Example value: "0.95,1.9,Infinity" or "0.049,0.05,0.051". Read only.
|
||||
static const char KEY_FOCUS_DISTANCES[];
|
||||
|
||||
// The image format for video frames. See CAMERA_MSG_VIDEO_FRAME in
|
||||
// frameworks/base/include/camera/Camera.h.
|
||||
// Example value: "yuv420sp" or PIXEL_FORMAT_XXX constants. Read only.
|
||||
static const char KEY_VIDEO_FRAME_FORMAT[];
|
||||
|
||||
// Value for KEY_ZOOM_SUPPORTED or KEY_SMOOTH_ZOOM_SUPPORTED.
|
||||
static const char TRUE[];
|
||||
|
||||
// Value for KEY_FOCUS_DISTANCES.
|
||||
static const char FOCUS_DISTANCE_INFINITY[];
|
||||
|
||||
// Values for white balance settings.
|
||||
static const char WHITE_BALANCE_AUTO[];
|
||||
static const char WHITE_BALANCE_INCANDESCENT[];
|
||||
static const char WHITE_BALANCE_FLUORESCENT[];
|
||||
static const char WHITE_BALANCE_WARM_FLUORESCENT[];
|
||||
static const char WHITE_BALANCE_DAYLIGHT[];
|
||||
static const char WHITE_BALANCE_CLOUDY_DAYLIGHT[];
|
||||
static const char WHITE_BALANCE_TWILIGHT[];
|
||||
static const char WHITE_BALANCE_SHADE[];
|
||||
|
||||
// Values for effect settings.
|
||||
static const char EFFECT_NONE[];
|
||||
static const char EFFECT_MONO[];
|
||||
static const char EFFECT_NEGATIVE[];
|
||||
static const char EFFECT_SOLARIZE[];
|
||||
static const char EFFECT_SEPIA[];
|
||||
static const char EFFECT_POSTERIZE[];
|
||||
static const char EFFECT_WHITEBOARD[];
|
||||
static const char EFFECT_BLACKBOARD[];
|
||||
static const char EFFECT_AQUA[];
|
||||
|
||||
// Values for antibanding settings.
|
||||
static const char ANTIBANDING_AUTO[];
|
||||
static const char ANTIBANDING_50HZ[];
|
||||
static const char ANTIBANDING_60HZ[];
|
||||
static const char ANTIBANDING_OFF[];
|
||||
|
||||
// Values for flash mode settings.
|
||||
// Flash will not be fired.
|
||||
static const char FLASH_MODE_OFF[];
|
||||
// Flash will be fired automatically when required. The flash may be fired
|
||||
// during preview, auto-focus, or snapshot depending on the driver.
|
||||
static const char FLASH_MODE_AUTO[];
|
||||
// Flash will always be fired during snapshot. The flash may also be
|
||||
// fired during preview or auto-focus depending on the driver.
|
||||
static const char FLASH_MODE_ON[];
|
||||
// Flash will be fired in red-eye reduction mode.
|
||||
static const char FLASH_MODE_RED_EYE[];
|
||||
// Constant emission of light during preview, auto-focus and snapshot.
|
||||
// This can also be used for video recording.
|
||||
static const char FLASH_MODE_TORCH[];
|
||||
|
||||
// Values for scene mode settings.
|
||||
static const char SCENE_MODE_AUTO[];
|
||||
static const char SCENE_MODE_ACTION[];
|
||||
static const char SCENE_MODE_PORTRAIT[];
|
||||
static const char SCENE_MODE_LANDSCAPE[];
|
||||
static const char SCENE_MODE_NIGHT[];
|
||||
static const char SCENE_MODE_NIGHT_PORTRAIT[];
|
||||
static const char SCENE_MODE_THEATRE[];
|
||||
static const char SCENE_MODE_BEACH[];
|
||||
static const char SCENE_MODE_SNOW[];
|
||||
static const char SCENE_MODE_SUNSET[];
|
||||
static const char SCENE_MODE_STEADYPHOTO[];
|
||||
static const char SCENE_MODE_FIREWORKS[];
|
||||
static const char SCENE_MODE_SPORTS[];
|
||||
static const char SCENE_MODE_PARTY[];
|
||||
static const char SCENE_MODE_CANDLELIGHT[];
|
||||
// Applications are looking for a barcode. Camera driver will be optimized
|
||||
// for barcode reading.
|
||||
static const char SCENE_MODE_BARCODE[];
|
||||
|
||||
// Formats for setPreviewFormat and setPictureFormat.
|
||||
static const char PIXEL_FORMAT_YUV422SP[];
|
||||
static const char PIXEL_FORMAT_YUV420SP[]; // NV21
|
||||
static const char PIXEL_FORMAT_YUV422I[]; // YUY2
|
||||
static const char PIXEL_FORMAT_RGB565[];
|
||||
static const char PIXEL_FORMAT_JPEG[];
|
||||
|
||||
// Values for focus mode settings.
|
||||
// Auto-focus mode. Applications should call
|
||||
// CameraHardwareInterface.autoFocus to start the focus in this mode.
|
||||
static const char FOCUS_MODE_AUTO[];
|
||||
// Focus is set at infinity. Applications should not call
|
||||
// CameraHardwareInterface.autoFocus in this mode.
|
||||
static const char FOCUS_MODE_INFINITY[];
|
||||
// Macro (close-up) focus mode. Applications should call
|
||||
// CameraHardwareInterface.autoFocus to start the focus in this mode.
|
||||
static const char FOCUS_MODE_MACRO[];
|
||||
// Focus is fixed. The camera is always in this mode if the focus is not
|
||||
// adjustable. If the camera has auto-focus, this mode can fix the
|
||||
// focus, which is usually at hyperfocal distance. Applications should
|
||||
// not call CameraHardwareInterface.autoFocus in this mode.
|
||||
static const char FOCUS_MODE_FIXED[];
|
||||
// Extended depth of field (EDOF). Focusing is done digitally and
|
||||
// continuously. Applications should not call
|
||||
// CameraHardwareInterface.autoFocus in this mode.
|
||||
static const char FOCUS_MODE_EDOF[];
|
||||
// Continuous auto focus mode intended for video recording. The camera
|
||||
// continuously tries to focus. This is ideal for shooting video.
|
||||
// Applications still can call CameraHardwareInterface.takePicture in this
|
||||
// mode but the subject may not be in focus. Auto focus starts when the
|
||||
// parameter is set. Applications should not call
|
||||
// CameraHardwareInterface.autoFocus in this mode. To stop continuous focus,
|
||||
// applications should change the focus mode to other modes.
|
||||
static const char FOCUS_MODE_CONTINUOUS_VIDEO[];
|
||||
|
||||
private:
|
||||
DefaultKeyedVector<String8,String8> mMap;
|
||||
};
|
||||
|
||||
}; // namespace android
|
||||
|
||||
#endif
|
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
* Copyright (C) 2008 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef ANDROID_HARDWARE_ICAMERA_APP_H
|
||||
#define ANDROID_HARDWARE_ICAMERA_APP_H
|
||||
|
||||
#include <utils/RefBase.h>
|
||||
#include <binder/IInterface.h>
|
||||
#include <binder/Parcel.h>
|
||||
#include <binder/IMemory.h>
|
||||
#include <utils/Timers.h>
|
||||
|
||||
namespace android {
|
||||
|
||||
class ICameraClient: public IInterface
|
||||
{
|
||||
public:
|
||||
DECLARE_META_INTERFACE(CameraClient);
|
||||
|
||||
virtual void notifyCallback(int32_t msgType, int32_t ext1, int32_t ext2) = 0;
|
||||
virtual void dataCallback(int32_t msgType, const sp<IMemory>& data) = 0;
|
||||
virtual void dataCallbackTimestamp(nsecs_t timestamp, int32_t msgType, const sp<IMemory>& data) = 0;
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
class BnCameraClient: public BnInterface<ICameraClient>
|
||||
{
|
||||
public:
|
||||
virtual status_t onTransact( uint32_t code,
|
||||
const Parcel& data,
|
||||
Parcel* reply,
|
||||
uint32_t flags = 0);
|
||||
};
|
||||
|
||||
}; // namespace android
|
||||
|
||||
#endif
|
|
@ -56,6 +56,10 @@ ifneq (Android,$(OS_TARGET))
|
|||
CPPSRCS += http_upload.cc
|
||||
endif
|
||||
|
||||
ifeq (gonk,$(MOZ_WIDGET_TOOLKIT))
|
||||
DEFINES += -DELFSIZE=32
|
||||
endif
|
||||
|
||||
HOST_CPPSRCS = \
|
||||
dump_symbols.cc \
|
||||
file_id.cc \
|
||||
|
|
|
@ -38,7 +38,10 @@
|
|||
DEPTH = ../..
|
||||
topsrcdir = @top_srcdir@
|
||||
srcdir = @srcdir@
|
||||
VPATH = @srcdir@
|
||||
VPATH = \
|
||||
$(srcdir) \
|
||||
$(srcdir)/libui \
|
||||
$(NULL)
|
||||
|
||||
include $(DEPTH)/config/autoconf.mk
|
||||
|
||||
|
@ -58,20 +61,35 @@ CPPSRCS = \
|
|||
nsWindow.cpp \
|
||||
nsLookAndFeel.cpp \
|
||||
nsIdleServiceGonk.cpp \
|
||||
EventHub.cpp \
|
||||
InputApplication.cpp \
|
||||
InputDispatcher.cpp \
|
||||
InputListener.cpp \
|
||||
InputReader.cpp \
|
||||
InputTransport.cpp \
|
||||
InputWindow.cpp \
|
||||
Keyboard.cpp \
|
||||
KeyCharacterMap.cpp \
|
||||
KeyLayoutMap.cpp \
|
||||
PixelFormat.cpp \
|
||||
VirtualKeyMap.cpp \
|
||||
$(NULL)
|
||||
|
||||
SHARED_LIBRARY_LIBS = ../xpwidgets/libxpwidgets_s.a
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
|
||||
DEFINES += -D_IMPL_NS_WIDGET
|
||||
DEFINES += -D_IMPL_NS_WIDGET -DHAVE_OFF64_T
|
||||
|
||||
LOCAL_INCLUDES += \
|
||||
-I$(topsrcdir)/widget/xpwidgets \
|
||||
-I$(topsrcdir)/widget/shared \
|
||||
-I$(topsrcdir)/dom/system/android \
|
||||
-I$(topsrcdir)/content/events/src \
|
||||
-I$(topsrcdir)/gfx/skia/include/core \
|
||||
-I$(topsrcdir)/gfx/skia/include/config \
|
||||
-I$(srcdir) \
|
||||
$(NULL)
|
||||
|
||||
|
||||
include $(topsrcdir)/ipc/chromium/chromium-config.mk
|
||||
|
|
|
@ -0,0 +1,52 @@
|
|||
/*
|
||||
* Copyright (C) 2007 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef ANDROID_UI_DISPLAY_INFO_H
|
||||
#define ANDROID_UI_DISPLAY_INFO_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "PixelFormat.h"
|
||||
|
||||
namespace android {
|
||||
|
||||
struct DisplayInfo {
|
||||
uint32_t w;
|
||||
uint32_t h;
|
||||
PixelFormatInfo pixelFormatInfo;
|
||||
uint8_t orientation;
|
||||
uint8_t reserved[3];
|
||||
float fps;
|
||||
float density;
|
||||
float xdpi;
|
||||
float ydpi;
|
||||
};
|
||||
|
||||
/* Display orientations as defined in Surface.java and ISurfaceComposer.h. */
|
||||
enum {
|
||||
DISPLAY_ORIENTATION_0 = 0,
|
||||
DISPLAY_ORIENTATION_90 = 1,
|
||||
DISPLAY_ORIENTATION_180 = 2,
|
||||
DISPLAY_ORIENTATION_270 = 3
|
||||
};
|
||||
|
||||
|
||||
}; // namespace android
|
||||
|
||||
#endif // ANDROID_COMPOSER_DISPLAY_INFO_H
|
||||
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -0,0 +1,377 @@
|
|||
/*
|
||||
* Copyright (C) 2005 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
//
|
||||
#ifndef _RUNTIME_EVENT_HUB_H
|
||||
#define _RUNTIME_EVENT_HUB_H
|
||||
|
||||
#include "Input.h"
|
||||
#include "Keyboard.h"
|
||||
#include "KeyLayoutMap.h"
|
||||
#include "KeyCharacterMap.h"
|
||||
#include "VirtualKeyMap.h"
|
||||
#include <utils/String8.h>
|
||||
#include <utils/threads.h>
|
||||
#include <utils/Log.h>
|
||||
#include <utils/threads.h>
|
||||
#include <utils/List.h>
|
||||
#include <utils/Errors.h>
|
||||
#include <utils/PropertyMap.h>
|
||||
#include <utils/Vector.h>
|
||||
#include <utils/KeyedVector.h>
|
||||
|
||||
#include <linux/input.h>
|
||||
#include <sys/epoll.h>
|
||||
|
||||
/* Convenience constants. */
|
||||
|
||||
#define BTN_FIRST 0x100 // first button scancode
|
||||
#define BTN_LAST 0x15f // last button scancode
|
||||
|
||||
namespace android {
|
||||
|
||||
/*
|
||||
* A raw event as retrieved from the EventHub.
|
||||
*/
|
||||
struct RawEvent {
|
||||
nsecs_t when;
|
||||
int32_t deviceId;
|
||||
int32_t type;
|
||||
int32_t scanCode;
|
||||
int32_t keyCode;
|
||||
int32_t value;
|
||||
uint32_t flags;
|
||||
};
|
||||
|
||||
/* Describes an absolute axis. */
|
||||
struct RawAbsoluteAxisInfo {
|
||||
bool valid; // true if the information is valid, false otherwise
|
||||
|
||||
int32_t minValue; // minimum value
|
||||
int32_t maxValue; // maximum value
|
||||
int32_t flat; // center flat position, eg. flat == 8 means center is between -8 and 8
|
||||
int32_t fuzz; // error tolerance, eg. fuzz == 4 means value is +/- 4 due to noise
|
||||
int32_t resolution; // resolution in units per mm or radians per mm
|
||||
|
||||
inline void clear() {
|
||||
valid = false;
|
||||
minValue = 0;
|
||||
maxValue = 0;
|
||||
flat = 0;
|
||||
fuzz = 0;
|
||||
resolution = 0;
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
* Input device classes.
|
||||
*/
|
||||
enum {
|
||||
/* The input device is a keyboard or has buttons. */
|
||||
INPUT_DEVICE_CLASS_KEYBOARD = 0x00000001,
|
||||
|
||||
/* The input device is an alpha-numeric keyboard (not just a dial pad). */
|
||||
INPUT_DEVICE_CLASS_ALPHAKEY = 0x00000002,
|
||||
|
||||
/* The input device is a touchscreen or a touchpad (either single-touch or multi-touch). */
|
||||
INPUT_DEVICE_CLASS_TOUCH = 0x00000004,
|
||||
|
||||
/* The input device is a cursor device such as a trackball or mouse. */
|
||||
INPUT_DEVICE_CLASS_CURSOR = 0x00000008,
|
||||
|
||||
/* The input device is a multi-touch touchscreen. */
|
||||
INPUT_DEVICE_CLASS_TOUCH_MT = 0x00000010,
|
||||
|
||||
/* The input device is a directional pad (implies keyboard, has DPAD keys). */
|
||||
INPUT_DEVICE_CLASS_DPAD = 0x00000020,
|
||||
|
||||
/* The input device is a gamepad (implies keyboard, has BUTTON keys). */
|
||||
INPUT_DEVICE_CLASS_GAMEPAD = 0x00000040,
|
||||
|
||||
/* The input device has switches. */
|
||||
INPUT_DEVICE_CLASS_SWITCH = 0x00000080,
|
||||
|
||||
/* The input device is a joystick (implies gamepad, has joystick absolute axes). */
|
||||
INPUT_DEVICE_CLASS_JOYSTICK = 0x00000100,
|
||||
|
||||
/* The input device is external (not built-in). */
|
||||
INPUT_DEVICE_CLASS_EXTERNAL = 0x80000000,
|
||||
};
|
||||
|
||||
/*
|
||||
* Gets the class that owns an axis, in cases where multiple classes might claim
|
||||
* the same axis for different purposes.
|
||||
*/
|
||||
extern uint32_t getAbsAxisUsage(int32_t axis, uint32_t deviceClasses);
|
||||
|
||||
/*
|
||||
* Grand Central Station for events.
|
||||
*
|
||||
* The event hub aggregates input events received across all known input
|
||||
* devices on the system, including devices that may be emulated by the simulator
|
||||
* environment. In addition, the event hub generates fake input events to indicate
|
||||
* when devices are added or removed.
|
||||
*
|
||||
* The event hub provides a stream of input events (via the getEvent function).
|
||||
* It also supports querying the current actual state of input devices such as identifying
|
||||
* which keys are currently down. Finally, the event hub keeps track of the capabilities of
|
||||
* individual input devices, such as their class and the set of key codes that they support.
|
||||
*/
|
||||
class EventHubInterface : public virtual RefBase {
|
||||
protected:
|
||||
EventHubInterface() { }
|
||||
virtual ~EventHubInterface() { }
|
||||
|
||||
public:
|
||||
// Synthetic raw event type codes produced when devices are added or removed.
|
||||
enum {
|
||||
// Sent when a device is added.
|
||||
DEVICE_ADDED = 0x10000000,
|
||||
// Sent when a device is removed.
|
||||
DEVICE_REMOVED = 0x20000000,
|
||||
// Sent when all added/removed devices from the most recent scan have been reported.
|
||||
// This event is always sent at least once.
|
||||
FINISHED_DEVICE_SCAN = 0x30000000,
|
||||
|
||||
FIRST_SYNTHETIC_EVENT = DEVICE_ADDED,
|
||||
};
|
||||
|
||||
virtual uint32_t getDeviceClasses(int32_t deviceId) const = 0;
|
||||
|
||||
virtual String8 getDeviceName(int32_t deviceId) const = 0;
|
||||
|
||||
virtual void getConfiguration(int32_t deviceId, PropertyMap* outConfiguration) const = 0;
|
||||
|
||||
virtual status_t getAbsoluteAxisInfo(int32_t deviceId, int axis,
|
||||
RawAbsoluteAxisInfo* outAxisInfo) const = 0;
|
||||
|
||||
virtual bool hasRelativeAxis(int32_t deviceId, int axis) const = 0;
|
||||
|
||||
virtual bool hasInputProperty(int32_t deviceId, int property) const = 0;
|
||||
|
||||
virtual status_t mapKey(int32_t deviceId, int scancode,
|
||||
int32_t* outKeycode, uint32_t* outFlags) const = 0;
|
||||
|
||||
virtual status_t mapAxis(int32_t deviceId, int scancode,
|
||||
AxisInfo* outAxisInfo) const = 0;
|
||||
|
||||
// Sets devices that are excluded from opening.
|
||||
// This can be used to ignore input devices for sensors.
|
||||
virtual void setExcludedDevices(const Vector<String8>& devices) = 0;
|
||||
|
||||
/*
|
||||
* Wait for events to become available and returns them.
|
||||
* After returning, the EventHub holds onto a wake lock until the next call to getEvent.
|
||||
* This ensures that the device will not go to sleep while the event is being processed.
|
||||
* If the device needs to remain awake longer than that, then the caller is responsible
|
||||
* for taking care of it (say, by poking the power manager user activity timer).
|
||||
*
|
||||
* The timeout is advisory only. If the device is asleep, it will not wake just to
|
||||
* service the timeout.
|
||||
*
|
||||
* Returns the number of events obtained, or 0 if the timeout expired.
|
||||
*/
|
||||
virtual size_t getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSize) = 0;
|
||||
|
||||
/*
|
||||
* Query current input state.
|
||||
*/
|
||||
virtual int32_t getScanCodeState(int32_t deviceId, int32_t scanCode) const = 0;
|
||||
virtual int32_t getKeyCodeState(int32_t deviceId, int32_t keyCode) const = 0;
|
||||
virtual int32_t getSwitchState(int32_t deviceId, int32_t sw) const = 0;
|
||||
virtual status_t getAbsoluteAxisValue(int32_t deviceId, int32_t axis,
|
||||
int32_t* outValue) const = 0;
|
||||
|
||||
/*
|
||||
* Examine key input devices for specific framework keycode support
|
||||
*/
|
||||
virtual bool markSupportedKeyCodes(int32_t deviceId, size_t numCodes, const int32_t* keyCodes,
|
||||
uint8_t* outFlags) const = 0;
|
||||
|
||||
virtual bool hasScanCode(int32_t deviceId, int32_t scanCode) const = 0;
|
||||
virtual bool hasLed(int32_t deviceId, int32_t led) const = 0;
|
||||
virtual void setLedState(int32_t deviceId, int32_t led, bool on) = 0;
|
||||
|
||||
virtual void getVirtualKeyDefinitions(int32_t deviceId,
|
||||
Vector<VirtualKeyDefinition>& outVirtualKeys) const = 0;
|
||||
|
||||
virtual String8 getKeyCharacterMapFile(int32_t deviceId) const = 0;
|
||||
|
||||
/* Requests the EventHub to reopen all input devices on the next call to getEvents(). */
|
||||
virtual void requestReopenDevices() = 0;
|
||||
|
||||
/* Wakes up getEvents() if it is blocked on a read. */
|
||||
virtual void wake() = 0;
|
||||
|
||||
/* Dump EventHub state to a string. */
|
||||
virtual void dump(String8& dump) = 0;
|
||||
|
||||
/* Called by the heatbeat to ensures that the reader has not deadlocked. */
|
||||
virtual void monitor() = 0;
|
||||
};
|
||||
|
||||
class EventHub : public EventHubInterface
|
||||
{
|
||||
public:
|
||||
EventHub();
|
||||
|
||||
virtual uint32_t getDeviceClasses(int32_t deviceId) const;
|
||||
|
||||
virtual String8 getDeviceName(int32_t deviceId) const;
|
||||
|
||||
virtual void getConfiguration(int32_t deviceId, PropertyMap* outConfiguration) const;
|
||||
|
||||
virtual status_t getAbsoluteAxisInfo(int32_t deviceId, int axis,
|
||||
RawAbsoluteAxisInfo* outAxisInfo) const;
|
||||
|
||||
virtual bool hasRelativeAxis(int32_t deviceId, int axis) const;
|
||||
|
||||
virtual bool hasInputProperty(int32_t deviceId, int property) const;
|
||||
|
||||
virtual status_t mapKey(int32_t deviceId, int scancode,
|
||||
int32_t* outKeycode, uint32_t* outFlags) const;
|
||||
|
||||
virtual status_t mapAxis(int32_t deviceId, int scancode,
|
||||
AxisInfo* outAxisInfo) const;
|
||||
|
||||
virtual void setExcludedDevices(const Vector<String8>& devices);
|
||||
|
||||
virtual int32_t getScanCodeState(int32_t deviceId, int32_t scanCode) const;
|
||||
virtual int32_t getKeyCodeState(int32_t deviceId, int32_t keyCode) const;
|
||||
virtual int32_t getSwitchState(int32_t deviceId, int32_t sw) const;
|
||||
virtual status_t getAbsoluteAxisValue(int32_t deviceId, int32_t axis, int32_t* outValue) const;
|
||||
|
||||
virtual bool markSupportedKeyCodes(int32_t deviceId, size_t numCodes,
|
||||
const int32_t* keyCodes, uint8_t* outFlags) const;
|
||||
|
||||
virtual size_t getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSize);
|
||||
|
||||
virtual bool hasScanCode(int32_t deviceId, int32_t scanCode) const;
|
||||
virtual bool hasLed(int32_t deviceId, int32_t led) const;
|
||||
virtual void setLedState(int32_t deviceId, int32_t led, bool on);
|
||||
|
||||
virtual void getVirtualKeyDefinitions(int32_t deviceId,
|
||||
Vector<VirtualKeyDefinition>& outVirtualKeys) const;
|
||||
|
||||
virtual String8 getKeyCharacterMapFile(int32_t deviceId) const;
|
||||
|
||||
virtual void requestReopenDevices();
|
||||
|
||||
virtual void wake();
|
||||
|
||||
virtual void dump(String8& dump);
|
||||
virtual void monitor();
|
||||
|
||||
protected:
|
||||
virtual ~EventHub();
|
||||
|
||||
private:
|
||||
struct Device {
|
||||
Device* next;
|
||||
|
||||
int fd;
|
||||
const int32_t id;
|
||||
const String8 path;
|
||||
const InputDeviceIdentifier identifier;
|
||||
|
||||
uint32_t classes;
|
||||
|
||||
uint8_t keyBitmask[(KEY_MAX + 1) / 8];
|
||||
uint8_t absBitmask[(ABS_MAX + 1) / 8];
|
||||
uint8_t relBitmask[(REL_MAX + 1) / 8];
|
||||
uint8_t swBitmask[(SW_MAX + 1) / 8];
|
||||
uint8_t ledBitmask[(LED_MAX + 1) / 8];
|
||||
uint8_t propBitmask[(INPUT_PROP_MAX + 1) / 8];
|
||||
|
||||
String8 configurationFile;
|
||||
PropertyMap* configuration;
|
||||
VirtualKeyMap* virtualKeyMap;
|
||||
KeyMap keyMap;
|
||||
|
||||
Device(int fd, int32_t id, const String8& path, const InputDeviceIdentifier& identifier);
|
||||
~Device();
|
||||
|
||||
void close();
|
||||
};
|
||||
|
||||
status_t openDeviceLocked(const char *devicePath);
|
||||
status_t closeDeviceByPathLocked(const char *devicePath);
|
||||
|
||||
void closeDeviceLocked(Device* device);
|
||||
void closeAllDevicesLocked();
|
||||
|
||||
status_t scanDirLocked(const char *dirname);
|
||||
void scanDevicesLocked();
|
||||
status_t readNotifyLocked();
|
||||
|
||||
Device* getDeviceLocked(int32_t deviceId) const;
|
||||
Device* getDeviceByPathLocked(const char* devicePath) const;
|
||||
|
||||
bool hasKeycodeLocked(Device* device, int keycode) const;
|
||||
|
||||
void loadConfigurationLocked(Device* device);
|
||||
status_t loadVirtualKeyMapLocked(Device* device);
|
||||
status_t loadKeyMapLocked(Device* device);
|
||||
|
||||
bool isExternalDeviceLocked(Device* device);
|
||||
|
||||
// Protect all internal state.
|
||||
mutable Mutex mLock;
|
||||
|
||||
// The actual id of the built-in keyboard, or -1 if none.
|
||||
// EventHub remaps the built-in keyboard to id 0 externally as required by the API.
|
||||
int32_t mBuiltInKeyboardId;
|
||||
|
||||
int32_t mNextDeviceId;
|
||||
|
||||
KeyedVector<int32_t, Device*> mDevices;
|
||||
|
||||
Device *mOpeningDevices;
|
||||
Device *mClosingDevices;
|
||||
|
||||
bool mNeedToSendFinishedDeviceScan;
|
||||
bool mNeedToReopenDevices;
|
||||
bool mNeedToScanDevices;
|
||||
Vector<String8> mExcludedDevices;
|
||||
|
||||
int mEpollFd;
|
||||
int mINotifyFd;
|
||||
int mWakeReadPipeFd;
|
||||
int mWakeWritePipeFd;
|
||||
|
||||
// Ids used for epoll notifications not associated with devices.
|
||||
static const uint32_t EPOLL_ID_INOTIFY = 0x80000001;
|
||||
static const uint32_t EPOLL_ID_WAKE = 0x80000002;
|
||||
|
||||
// Epoll FD list size hint.
|
||||
static const int EPOLL_SIZE_HINT = 8;
|
||||
|
||||
// Maximum number of signalled FDs to handle at a time.
|
||||
static const int EPOLL_MAX_EVENTS = 16;
|
||||
|
||||
// The array of pending epoll events and the index of the next event to be handled.
|
||||
struct epoll_event mPendingEventItems[EPOLL_MAX_EVENTS];
|
||||
size_t mPendingEventCount;
|
||||
size_t mPendingEventIndex;
|
||||
bool mPendingINotify;
|
||||
|
||||
// Set to the number of CPUs.
|
||||
int32_t mNumCpus;
|
||||
};
|
||||
|
||||
}; // namespace android
|
||||
|
||||
#endif // _RUNTIME_EVENT_HUB_H
|
|
@ -0,0 +1,897 @@
|
|||
/*
|
||||
* Copyright (C) 2010 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef _UI_INPUT_H
|
||||
#define _UI_INPUT_H
|
||||
|
||||
/**
|
||||
* Native input event structures.
|
||||
*/
|
||||
|
||||
#include <android/input.h>
|
||||
#include <utils/Vector.h>
|
||||
#include <utils/KeyedVector.h>
|
||||
#include <utils/Timers.h>
|
||||
#include <utils/RefBase.h>
|
||||
#include <utils/String8.h>
|
||||
#include <utils/BitSet.h>
|
||||
|
||||
#ifdef HAVE_ANDROID_OS
|
||||
class SkMatrix;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Additional private constants not defined in ndk/ui/input.h.
|
||||
*/
|
||||
enum {
|
||||
/* Private control to determine when an app is tracking a key sequence. */
|
||||
AKEY_EVENT_FLAG_START_TRACKING = 0x40000000,
|
||||
|
||||
/* Key event is inconsistent with previously sent key events. */
|
||||
AKEY_EVENT_FLAG_TAINTED = 0x80000000,
|
||||
};
|
||||
|
||||
enum {
|
||||
/* Motion event is inconsistent with previously sent motion events. */
|
||||
AMOTION_EVENT_FLAG_TAINTED = 0x80000000,
|
||||
};
|
||||
|
||||
enum {
|
||||
/*
|
||||
* Indicates that an input device has switches.
|
||||
* This input source flag is hidden from the API because switches are only used by the system
|
||||
* and applications have no way to interact with them.
|
||||
*/
|
||||
AINPUT_SOURCE_SWITCH = 0x80000000,
|
||||
};
|
||||
|
||||
/*
|
||||
* SystemUiVisibility constants from View.
|
||||
*/
|
||||
enum {
|
||||
ASYSTEM_UI_VISIBILITY_STATUS_BAR_VISIBLE = 0,
|
||||
ASYSTEM_UI_VISIBILITY_STATUS_BAR_HIDDEN = 0x00000001,
|
||||
};
|
||||
|
||||
/*
|
||||
* Maximum number of pointers supported per motion event.
|
||||
* Smallest number of pointers is 1.
|
||||
* (We want at least 10 but some touch controllers obstensibly configured for 10 pointers
|
||||
* will occasionally emit 11. There is not much harm making this constant bigger.)
|
||||
*/
|
||||
#define MAX_POINTERS 16
|
||||
|
||||
/*
|
||||
* Maximum pointer id value supported in a motion event.
|
||||
* Smallest pointer id is 0.
|
||||
* (This is limited by our use of BitSet32 to track pointer assignments.)
|
||||
*/
|
||||
#define MAX_POINTER_ID 31
|
||||
|
||||
/*
|
||||
* Declare a concrete type for the NDK's input event forward declaration.
|
||||
*/
|
||||
struct AInputEvent {
|
||||
virtual ~AInputEvent() { }
|
||||
};
|
||||
|
||||
/*
|
||||
* Declare a concrete type for the NDK's input device forward declaration.
|
||||
*/
|
||||
struct AInputDevice {
|
||||
virtual ~AInputDevice() { }
|
||||
};
|
||||
|
||||
|
||||
namespace android {
|
||||
|
||||
#ifdef HAVE_ANDROID_OS
|
||||
class Parcel;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Flags that flow alongside events in the input dispatch system to help with certain
|
||||
* policy decisions such as waking from device sleep.
|
||||
*
|
||||
* These flags are also defined in frameworks/base/core/java/android/view/WindowManagerPolicy.java.
|
||||
*/
|
||||
enum {
|
||||
/* These flags originate in RawEvents and are generally set in the key map.
|
||||
* NOTE: If you edit these flags, also edit labels in KeycodeLabels.h. */
|
||||
|
||||
POLICY_FLAG_WAKE = 0x00000001,
|
||||
POLICY_FLAG_WAKE_DROPPED = 0x00000002,
|
||||
POLICY_FLAG_SHIFT = 0x00000004,
|
||||
POLICY_FLAG_CAPS_LOCK = 0x00000008,
|
||||
POLICY_FLAG_ALT = 0x00000010,
|
||||
POLICY_FLAG_ALT_GR = 0x00000020,
|
||||
POLICY_FLAG_MENU = 0x00000040,
|
||||
POLICY_FLAG_LAUNCHER = 0x00000080,
|
||||
POLICY_FLAG_VIRTUAL = 0x00000100,
|
||||
POLICY_FLAG_FUNCTION = 0x00000200,
|
||||
|
||||
POLICY_FLAG_RAW_MASK = 0x0000ffff,
|
||||
|
||||
/* These flags are set by the input dispatcher. */
|
||||
|
||||
// Indicates that the input event was injected.
|
||||
POLICY_FLAG_INJECTED = 0x01000000,
|
||||
|
||||
// Indicates that the input event is from a trusted source such as a directly attached
|
||||
// input device or an application with system-wide event injection permission.
|
||||
POLICY_FLAG_TRUSTED = 0x02000000,
|
||||
|
||||
// Indicates that the input event has passed through an input filter.
|
||||
POLICY_FLAG_FILTERED = 0x04000000,
|
||||
|
||||
// Disables automatic key repeating behavior.
|
||||
POLICY_FLAG_DISABLE_KEY_REPEAT = 0x08000000,
|
||||
|
||||
/* These flags are set by the input reader policy as it intercepts each event. */
|
||||
|
||||
// Indicates that the screen was off when the event was received and the event
|
||||
// should wake the device.
|
||||
POLICY_FLAG_WOKE_HERE = 0x10000000,
|
||||
|
||||
// Indicates that the screen was dim when the event was received and the event
|
||||
// should brighten the device.
|
||||
POLICY_FLAG_BRIGHT_HERE = 0x20000000,
|
||||
|
||||
// Indicates that the event should be dispatched to applications.
|
||||
// The input event should still be sent to the InputDispatcher so that it can see all
|
||||
// input events received include those that it will not deliver.
|
||||
POLICY_FLAG_PASS_TO_USER = 0x40000000,
|
||||
};
|
||||
|
||||
/*
|
||||
* Describes the basic configuration of input devices that are present.
|
||||
*/
|
||||
struct InputConfiguration {
|
||||
enum {
|
||||
TOUCHSCREEN_UNDEFINED = 0,
|
||||
TOUCHSCREEN_NOTOUCH = 1,
|
||||
TOUCHSCREEN_STYLUS = 2,
|
||||
TOUCHSCREEN_FINGER = 3
|
||||
};
|
||||
|
||||
enum {
|
||||
KEYBOARD_UNDEFINED = 0,
|
||||
KEYBOARD_NOKEYS = 1,
|
||||
KEYBOARD_QWERTY = 2,
|
||||
KEYBOARD_12KEY = 3
|
||||
};
|
||||
|
||||
enum {
|
||||
NAVIGATION_UNDEFINED = 0,
|
||||
NAVIGATION_NONAV = 1,
|
||||
NAVIGATION_DPAD = 2,
|
||||
NAVIGATION_TRACKBALL = 3,
|
||||
NAVIGATION_WHEEL = 4
|
||||
};
|
||||
|
||||
int32_t touchScreen;
|
||||
int32_t keyboard;
|
||||
int32_t navigation;
|
||||
};
|
||||
|
||||
/*
|
||||
* Pointer coordinate data.
|
||||
*/
|
||||
struct PointerCoords {
|
||||
enum { MAX_AXES = 14 }; // 14 so that sizeof(PointerCoords) == 64
|
||||
|
||||
// Bitfield of axes that are present in this structure.
|
||||
uint64_t bits;
|
||||
|
||||
// Values of axes that are stored in this structure packed in order by axis id
|
||||
// for each axis that is present in the structure according to 'bits'.
|
||||
float values[MAX_AXES];
|
||||
|
||||
inline void clear() {
|
||||
bits = 0;
|
||||
}
|
||||
|
||||
float getAxisValue(int32_t axis) const;
|
||||
status_t setAxisValue(int32_t axis, float value);
|
||||
|
||||
void scale(float scale);
|
||||
|
||||
inline float getX() const {
|
||||
return getAxisValue(AMOTION_EVENT_AXIS_X);
|
||||
}
|
||||
|
||||
inline float getY() const {
|
||||
return getAxisValue(AMOTION_EVENT_AXIS_Y);
|
||||
}
|
||||
|
||||
#ifdef HAVE_ANDROID_OS
|
||||
status_t readFromParcel(Parcel* parcel);
|
||||
status_t writeToParcel(Parcel* parcel) const;
|
||||
#endif
|
||||
|
||||
bool operator==(const PointerCoords& other) const;
|
||||
inline bool operator!=(const PointerCoords& other) const {
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
void copyFrom(const PointerCoords& other);
|
||||
|
||||
private:
|
||||
void tooManyAxes(int axis);
|
||||
};
|
||||
|
||||
/*
|
||||
* Pointer property data.
|
||||
*/
|
||||
struct PointerProperties {
|
||||
// The id of the pointer.
|
||||
int32_t id;
|
||||
|
||||
// The pointer tool type.
|
||||
int32_t toolType;
|
||||
|
||||
inline void clear() {
|
||||
id = -1;
|
||||
toolType = 0;
|
||||
}
|
||||
|
||||
bool operator==(const PointerProperties& other) const;
|
||||
inline bool operator!=(const PointerProperties& other) const {
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
void copyFrom(const PointerProperties& other);
|
||||
};
|
||||
|
||||
/*
|
||||
* Input events.
|
||||
*/
|
||||
class InputEvent : public AInputEvent {
|
||||
public:
|
||||
virtual ~InputEvent() { }
|
||||
|
||||
virtual int32_t getType() const = 0;
|
||||
|
||||
inline int32_t getDeviceId() const { return mDeviceId; }
|
||||
|
||||
inline int32_t getSource() const { return mSource; }
|
||||
|
||||
inline void setSource(int32_t source) { mSource = source; }
|
||||
|
||||
protected:
|
||||
void initialize(int32_t deviceId, int32_t source);
|
||||
void initialize(const InputEvent& from);
|
||||
|
||||
int32_t mDeviceId;
|
||||
int32_t mSource;
|
||||
};
|
||||
|
||||
/*
|
||||
* Key events.
|
||||
*/
|
||||
class KeyEvent : public InputEvent {
|
||||
public:
|
||||
virtual ~KeyEvent() { }
|
||||
|
||||
virtual int32_t getType() const { return AINPUT_EVENT_TYPE_KEY; }
|
||||
|
||||
inline int32_t getAction() const { return mAction; }
|
||||
|
||||
inline int32_t getFlags() const { return mFlags; }
|
||||
|
||||
inline int32_t getKeyCode() const { return mKeyCode; }
|
||||
|
||||
inline int32_t getScanCode() const { return mScanCode; }
|
||||
|
||||
inline int32_t getMetaState() const { return mMetaState; }
|
||||
|
||||
inline int32_t getRepeatCount() const { return mRepeatCount; }
|
||||
|
||||
inline nsecs_t getDownTime() const { return mDownTime; }
|
||||
|
||||
inline nsecs_t getEventTime() const { return mEventTime; }
|
||||
|
||||
// Return true if this event may have a default action implementation.
|
||||
static bool hasDefaultAction(int32_t keyCode);
|
||||
bool hasDefaultAction() const;
|
||||
|
||||
// Return true if this event represents a system key.
|
||||
static bool isSystemKey(int32_t keyCode);
|
||||
bool isSystemKey() const;
|
||||
|
||||
void initialize(
|
||||
int32_t deviceId,
|
||||
int32_t source,
|
||||
int32_t action,
|
||||
int32_t flags,
|
||||
int32_t keyCode,
|
||||
int32_t scanCode,
|
||||
int32_t metaState,
|
||||
int32_t repeatCount,
|
||||
nsecs_t downTime,
|
||||
nsecs_t eventTime);
|
||||
void initialize(const KeyEvent& from);
|
||||
|
||||
protected:
|
||||
int32_t mAction;
|
||||
int32_t mFlags;
|
||||
int32_t mKeyCode;
|
||||
int32_t mScanCode;
|
||||
int32_t mMetaState;
|
||||
int32_t mRepeatCount;
|
||||
nsecs_t mDownTime;
|
||||
nsecs_t mEventTime;
|
||||
};
|
||||
|
||||
/*
|
||||
* Motion events.
|
||||
*/
|
||||
class MotionEvent : public InputEvent {
|
||||
public:
|
||||
virtual ~MotionEvent() { }
|
||||
|
||||
virtual int32_t getType() const { return AINPUT_EVENT_TYPE_MOTION; }
|
||||
|
||||
inline int32_t getAction() const { return mAction; }
|
||||
|
||||
inline int32_t getActionMasked() const { return mAction & AMOTION_EVENT_ACTION_MASK; }
|
||||
|
||||
inline int32_t getActionIndex() const {
|
||||
return (mAction & AMOTION_EVENT_ACTION_POINTER_INDEX_MASK)
|
||||
>> AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT;
|
||||
}
|
||||
|
||||
inline void setAction(int32_t action) { mAction = action; }
|
||||
|
||||
inline int32_t getFlags() const { return mFlags; }
|
||||
|
||||
inline void setFlags(int32_t flags) { mFlags = flags; }
|
||||
|
||||
inline int32_t getEdgeFlags() const { return mEdgeFlags; }
|
||||
|
||||
inline void setEdgeFlags(int32_t edgeFlags) { mEdgeFlags = edgeFlags; }
|
||||
|
||||
inline int32_t getMetaState() const { return mMetaState; }
|
||||
|
||||
inline void setMetaState(int32_t metaState) { mMetaState = metaState; }
|
||||
|
||||
inline int32_t getButtonState() const { return mButtonState; }
|
||||
|
||||
inline float getXOffset() const { return mXOffset; }
|
||||
|
||||
inline float getYOffset() const { return mYOffset; }
|
||||
|
||||
inline float getXPrecision() const { return mXPrecision; }
|
||||
|
||||
inline float getYPrecision() const { return mYPrecision; }
|
||||
|
||||
inline nsecs_t getDownTime() const { return mDownTime; }
|
||||
|
||||
inline void setDownTime(nsecs_t downTime) { mDownTime = downTime; }
|
||||
|
||||
inline size_t getPointerCount() const { return mPointerProperties.size(); }
|
||||
|
||||
inline const PointerProperties* getPointerProperties(size_t pointerIndex) const {
|
||||
return &mPointerProperties[pointerIndex];
|
||||
}
|
||||
|
||||
inline int32_t getPointerId(size_t pointerIndex) const {
|
||||
return mPointerProperties[pointerIndex].id;
|
||||
}
|
||||
|
||||
inline int32_t getToolType(size_t pointerIndex) const {
|
||||
return mPointerProperties[pointerIndex].toolType;
|
||||
}
|
||||
|
||||
inline nsecs_t getEventTime() const { return mSampleEventTimes[getHistorySize()]; }
|
||||
|
||||
const PointerCoords* getRawPointerCoords(size_t pointerIndex) const;
|
||||
|
||||
float getRawAxisValue(int32_t axis, size_t pointerIndex) const;
|
||||
|
||||
inline float getRawX(size_t pointerIndex) const {
|
||||
return getRawAxisValue(AMOTION_EVENT_AXIS_X, pointerIndex);
|
||||
}
|
||||
|
||||
inline float getRawY(size_t pointerIndex) const {
|
||||
return getRawAxisValue(AMOTION_EVENT_AXIS_Y, pointerIndex);
|
||||
}
|
||||
|
||||
float getAxisValue(int32_t axis, size_t pointerIndex) const;
|
||||
|
||||
inline float getX(size_t pointerIndex) const {
|
||||
return getAxisValue(AMOTION_EVENT_AXIS_X, pointerIndex);
|
||||
}
|
||||
|
||||
inline float getY(size_t pointerIndex) const {
|
||||
return getAxisValue(AMOTION_EVENT_AXIS_Y, pointerIndex);
|
||||
}
|
||||
|
||||
inline float getPressure(size_t pointerIndex) const {
|
||||
return getAxisValue(AMOTION_EVENT_AXIS_PRESSURE, pointerIndex);
|
||||
}
|
||||
|
||||
inline float getSize(size_t pointerIndex) const {
|
||||
return getAxisValue(AMOTION_EVENT_AXIS_SIZE, pointerIndex);
|
||||
}
|
||||
|
||||
inline float getTouchMajor(size_t pointerIndex) const {
|
||||
return getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR, pointerIndex);
|
||||
}
|
||||
|
||||
inline float getTouchMinor(size_t pointerIndex) const {
|
||||
return getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR, pointerIndex);
|
||||
}
|
||||
|
||||
inline float getToolMajor(size_t pointerIndex) const {
|
||||
return getAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR, pointerIndex);
|
||||
}
|
||||
|
||||
inline float getToolMinor(size_t pointerIndex) const {
|
||||
return getAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR, pointerIndex);
|
||||
}
|
||||
|
||||
inline float getOrientation(size_t pointerIndex) const {
|
||||
return getAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, pointerIndex);
|
||||
}
|
||||
|
||||
inline size_t getHistorySize() const { return mSampleEventTimes.size() - 1; }
|
||||
|
||||
inline nsecs_t getHistoricalEventTime(size_t historicalIndex) const {
|
||||
return mSampleEventTimes[historicalIndex];
|
||||
}
|
||||
|
||||
const PointerCoords* getHistoricalRawPointerCoords(
|
||||
size_t pointerIndex, size_t historicalIndex) const;
|
||||
|
||||
float getHistoricalRawAxisValue(int32_t axis, size_t pointerIndex,
|
||||
size_t historicalIndex) const;
|
||||
|
||||
inline float getHistoricalRawX(size_t pointerIndex, size_t historicalIndex) const {
|
||||
return getHistoricalRawAxisValue(
|
||||
AMOTION_EVENT_AXIS_X, pointerIndex, historicalIndex);
|
||||
}
|
||||
|
||||
inline float getHistoricalRawY(size_t pointerIndex, size_t historicalIndex) const {
|
||||
return getHistoricalRawAxisValue(
|
||||
AMOTION_EVENT_AXIS_Y, pointerIndex, historicalIndex);
|
||||
}
|
||||
|
||||
float getHistoricalAxisValue(int32_t axis, size_t pointerIndex, size_t historicalIndex) const;
|
||||
|
||||
inline float getHistoricalX(size_t pointerIndex, size_t historicalIndex) const {
|
||||
return getHistoricalAxisValue(
|
||||
AMOTION_EVENT_AXIS_X, pointerIndex, historicalIndex);
|
||||
}
|
||||
|
||||
inline float getHistoricalY(size_t pointerIndex, size_t historicalIndex) const {
|
||||
return getHistoricalAxisValue(
|
||||
AMOTION_EVENT_AXIS_Y, pointerIndex, historicalIndex);
|
||||
}
|
||||
|
||||
inline float getHistoricalPressure(size_t pointerIndex, size_t historicalIndex) const {
|
||||
return getHistoricalAxisValue(
|
||||
AMOTION_EVENT_AXIS_PRESSURE, pointerIndex, historicalIndex);
|
||||
}
|
||||
|
||||
inline float getHistoricalSize(size_t pointerIndex, size_t historicalIndex) const {
|
||||
return getHistoricalAxisValue(
|
||||
AMOTION_EVENT_AXIS_SIZE, pointerIndex, historicalIndex);
|
||||
}
|
||||
|
||||
inline float getHistoricalTouchMajor(size_t pointerIndex, size_t historicalIndex) const {
|
||||
return getHistoricalAxisValue(
|
||||
AMOTION_EVENT_AXIS_TOUCH_MAJOR, pointerIndex, historicalIndex);
|
||||
}
|
||||
|
||||
inline float getHistoricalTouchMinor(size_t pointerIndex, size_t historicalIndex) const {
|
||||
return getHistoricalAxisValue(
|
||||
AMOTION_EVENT_AXIS_TOUCH_MINOR, pointerIndex, historicalIndex);
|
||||
}
|
||||
|
||||
inline float getHistoricalToolMajor(size_t pointerIndex, size_t historicalIndex) const {
|
||||
return getHistoricalAxisValue(
|
||||
AMOTION_EVENT_AXIS_TOOL_MAJOR, pointerIndex, historicalIndex);
|
||||
}
|
||||
|
||||
inline float getHistoricalToolMinor(size_t pointerIndex, size_t historicalIndex) const {
|
||||
return getHistoricalAxisValue(
|
||||
AMOTION_EVENT_AXIS_TOOL_MINOR, pointerIndex, historicalIndex);
|
||||
}
|
||||
|
||||
inline float getHistoricalOrientation(size_t pointerIndex, size_t historicalIndex) const {
|
||||
return getHistoricalAxisValue(
|
||||
AMOTION_EVENT_AXIS_ORIENTATION, pointerIndex, historicalIndex);
|
||||
}
|
||||
|
||||
ssize_t findPointerIndex(int32_t pointerId) const;
|
||||
|
||||
void initialize(
|
||||
int32_t deviceId,
|
||||
int32_t source,
|
||||
int32_t action,
|
||||
int32_t flags,
|
||||
int32_t edgeFlags,
|
||||
int32_t metaState,
|
||||
int32_t buttonState,
|
||||
float xOffset,
|
||||
float yOffset,
|
||||
float xPrecision,
|
||||
float yPrecision,
|
||||
nsecs_t downTime,
|
||||
nsecs_t eventTime,
|
||||
size_t pointerCount,
|
||||
const PointerProperties* pointerProperties,
|
||||
const PointerCoords* pointerCoords);
|
||||
|
||||
void copyFrom(const MotionEvent* other, bool keepHistory);
|
||||
|
||||
void addSample(
|
||||
nsecs_t eventTime,
|
||||
const PointerCoords* pointerCoords);
|
||||
|
||||
void offsetLocation(float xOffset, float yOffset);
|
||||
|
||||
void scale(float scaleFactor);
|
||||
|
||||
#ifdef HAVE_ANDROID_OS
|
||||
void transform(const SkMatrix* matrix);
|
||||
|
||||
status_t readFromParcel(Parcel* parcel);
|
||||
status_t writeToParcel(Parcel* parcel) const;
|
||||
#endif
|
||||
|
||||
static bool isTouchEvent(int32_t source, int32_t action);
|
||||
inline bool isTouchEvent() const {
|
||||
return isTouchEvent(mSource, mAction);
|
||||
}
|
||||
|
||||
// Low-level accessors.
|
||||
inline const PointerProperties* getPointerProperties() const {
|
||||
return mPointerProperties.array();
|
||||
}
|
||||
inline const nsecs_t* getSampleEventTimes() const { return mSampleEventTimes.array(); }
|
||||
inline const PointerCoords* getSamplePointerCoords() const {
|
||||
return mSamplePointerCoords.array();
|
||||
}
|
||||
|
||||
protected:
|
||||
int32_t mAction;
|
||||
int32_t mFlags;
|
||||
int32_t mEdgeFlags;
|
||||
int32_t mMetaState;
|
||||
int32_t mButtonState;
|
||||
float mXOffset;
|
||||
float mYOffset;
|
||||
float mXPrecision;
|
||||
float mYPrecision;
|
||||
nsecs_t mDownTime;
|
||||
Vector<PointerProperties> mPointerProperties;
|
||||
Vector<nsecs_t> mSampleEventTimes;
|
||||
Vector<PointerCoords> mSamplePointerCoords;
|
||||
};
|
||||
|
||||
/*
|
||||
* Input event factory.
|
||||
*/
|
||||
class InputEventFactoryInterface {
|
||||
protected:
|
||||
virtual ~InputEventFactoryInterface() { }
|
||||
|
||||
public:
|
||||
InputEventFactoryInterface() { }
|
||||
|
||||
virtual KeyEvent* createKeyEvent() = 0;
|
||||
virtual MotionEvent* createMotionEvent() = 0;
|
||||
};
|
||||
|
||||
/*
|
||||
* A simple input event factory implementation that uses a single preallocated instance
|
||||
* of each type of input event that are reused for each request.
|
||||
*/
|
||||
class PreallocatedInputEventFactory : public InputEventFactoryInterface {
|
||||
public:
|
||||
PreallocatedInputEventFactory() { }
|
||||
virtual ~PreallocatedInputEventFactory() { }
|
||||
|
||||
virtual KeyEvent* createKeyEvent() { return & mKeyEvent; }
|
||||
virtual MotionEvent* createMotionEvent() { return & mMotionEvent; }
|
||||
|
||||
private:
|
||||
KeyEvent mKeyEvent;
|
||||
MotionEvent mMotionEvent;
|
||||
};
|
||||
|
||||
/*
|
||||
* Calculates the velocity of pointer movements over time.
|
||||
*/
|
||||
class VelocityTracker {
|
||||
public:
|
||||
// Default polynomial degree. (used by getVelocity)
|
||||
static const uint32_t DEFAULT_DEGREE = 2;
|
||||
|
||||
// Default sample horizon. (used by getVelocity)
|
||||
// We don't use too much history by default since we want to react to quick
|
||||
// changes in direction.
|
||||
static const nsecs_t DEFAULT_HORIZON = 100 * 1000000; // 100 ms
|
||||
|
||||
struct Position {
|
||||
float x, y;
|
||||
};
|
||||
|
||||
struct Estimator {
|
||||
static const size_t MAX_DEGREE = 2;
|
||||
|
||||
// Polynomial coefficients describing motion in X and Y.
|
||||
float xCoeff[MAX_DEGREE + 1], yCoeff[MAX_DEGREE + 1];
|
||||
|
||||
// Polynomial degree (number of coefficients), or zero if no information is
|
||||
// available.
|
||||
uint32_t degree;
|
||||
|
||||
// Confidence (coefficient of determination), between 0 (no fit) and 1 (perfect fit).
|
||||
float confidence;
|
||||
|
||||
inline void clear() {
|
||||
degree = 0;
|
||||
confidence = 0;
|
||||
for (size_t i = 0; i <= MAX_DEGREE; i++) {
|
||||
xCoeff[i] = 0;
|
||||
yCoeff[i] = 0;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
VelocityTracker();
|
||||
|
||||
// Resets the velocity tracker state.
|
||||
void clear();
|
||||
|
||||
// Resets the velocity tracker state for specific pointers.
|
||||
// Call this method when some pointers have changed and may be reusing
|
||||
// an id that was assigned to a different pointer earlier.
|
||||
void clearPointers(BitSet32 idBits);
|
||||
|
||||
// Adds movement information for a set of pointers.
|
||||
// The idBits bitfield specifies the pointer ids of the pointers whose positions
|
||||
// are included in the movement.
|
||||
// The positions array contains position information for each pointer in order by
|
||||
// increasing id. Its size should be equal to the number of one bits in idBits.
|
||||
void addMovement(nsecs_t eventTime, BitSet32 idBits, const Position* positions);
|
||||
|
||||
// Adds movement information for all pointers in a MotionEvent, including historical samples.
|
||||
void addMovement(const MotionEvent* event);
|
||||
|
||||
// Gets the velocity of the specified pointer id in position units per second.
|
||||
// Returns false and sets the velocity components to zero if there is
|
||||
// insufficient movement information for the pointer.
|
||||
bool getVelocity(uint32_t id, float* outVx, float* outVy) const;
|
||||
|
||||
// Gets a quadratic estimator for the movements of the specified pointer id.
|
||||
// Returns false and clears the estimator if there is no information available
|
||||
// about the pointer.
|
||||
bool getEstimator(uint32_t id, uint32_t degree, nsecs_t horizon,
|
||||
Estimator* outEstimator) const;
|
||||
|
||||
// Gets the active pointer id, or -1 if none.
|
||||
inline int32_t getActivePointerId() const { return mActivePointerId; }
|
||||
|
||||
// Gets a bitset containing all pointer ids from the most recent movement.
|
||||
inline BitSet32 getCurrentPointerIdBits() const { return mMovements[mIndex].idBits; }
|
||||
|
||||
private:
|
||||
// Number of samples to keep.
|
||||
static const uint32_t HISTORY_SIZE = 20;
|
||||
|
||||
struct Movement {
|
||||
nsecs_t eventTime;
|
||||
BitSet32 idBits;
|
||||
Position positions[MAX_POINTERS];
|
||||
|
||||
inline const Position& getPosition(uint32_t id) const {
|
||||
return positions[idBits.getIndexOfBit(id)];
|
||||
}
|
||||
};
|
||||
|
||||
uint32_t mIndex;
|
||||
Movement mMovements[HISTORY_SIZE];
|
||||
int32_t mActivePointerId;
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* Specifies parameters that govern pointer or wheel acceleration.
|
||||
*/
|
||||
struct VelocityControlParameters {
|
||||
// A scale factor that is multiplied with the raw velocity deltas
|
||||
// prior to applying any other velocity control factors. The scale
|
||||
// factor should be used to adapt the input device resolution
|
||||
// (eg. counts per inch) to the output device resolution (eg. pixels per inch).
|
||||
//
|
||||
// Must be a positive value.
|
||||
// Default is 1.0 (no scaling).
|
||||
float scale;
|
||||
|
||||
// The scaled speed at which acceleration begins to be applied.
|
||||
// This value establishes the upper bound of a low speed regime for
|
||||
// small precise motions that are performed without any acceleration.
|
||||
//
|
||||
// Must be a non-negative value.
|
||||
// Default is 0.0 (no low threshold).
|
||||
float lowThreshold;
|
||||
|
||||
// The scaled speed at which maximum acceleration is applied.
|
||||
// The difference between highThreshold and lowThreshold controls
|
||||
// the range of speeds over which the acceleration factor is interpolated.
|
||||
// The wider the range, the smoother the acceleration.
|
||||
//
|
||||
// Must be a non-negative value greater than or equal to lowThreshold.
|
||||
// Default is 0.0 (no high threshold).
|
||||
float highThreshold;
|
||||
|
||||
// The acceleration factor.
|
||||
// When the speed is above the low speed threshold, the velocity will scaled
|
||||
// by an interpolated value between 1.0 and this amount.
|
||||
//
|
||||
// Must be a positive greater than or equal to 1.0.
|
||||
// Default is 1.0 (no acceleration).
|
||||
float acceleration;
|
||||
|
||||
VelocityControlParameters() :
|
||||
scale(1.0f), lowThreshold(0.0f), highThreshold(0.0f), acceleration(1.0f) {
|
||||
}
|
||||
|
||||
VelocityControlParameters(float scale, float lowThreshold,
|
||||
float highThreshold, float acceleration) :
|
||||
scale(scale), lowThreshold(lowThreshold),
|
||||
highThreshold(highThreshold), acceleration(acceleration) {
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
* Implements mouse pointer and wheel speed control and acceleration.
|
||||
*/
|
||||
class VelocityControl {
|
||||
public:
|
||||
VelocityControl();
|
||||
|
||||
/* Sets the various parameters. */
|
||||
void setParameters(const VelocityControlParameters& parameters);
|
||||
|
||||
/* Resets the current movement counters to zero.
|
||||
* This has the effect of nullifying any acceleration. */
|
||||
void reset();
|
||||
|
||||
/* Translates a raw movement delta into an appropriately
|
||||
* scaled / accelerated delta based on the current velocity. */
|
||||
void move(nsecs_t eventTime, float* deltaX, float* deltaY);
|
||||
|
||||
private:
|
||||
// If no movements are received within this amount of time,
|
||||
// we assume the movement has stopped and reset the movement counters.
|
||||
static const nsecs_t STOP_TIME = 500 * 1000000; // 500 ms
|
||||
|
||||
VelocityControlParameters mParameters;
|
||||
|
||||
nsecs_t mLastMovementTime;
|
||||
VelocityTracker::Position mRawPosition;
|
||||
VelocityTracker mVelocityTracker;
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* Describes the characteristics and capabilities of an input device.
|
||||
*/
|
||||
class InputDeviceInfo {
|
||||
public:
|
||||
InputDeviceInfo();
|
||||
InputDeviceInfo(const InputDeviceInfo& other);
|
||||
~InputDeviceInfo();
|
||||
|
||||
struct MotionRange {
|
||||
int32_t axis;
|
||||
uint32_t source;
|
||||
float min;
|
||||
float max;
|
||||
float flat;
|
||||
float fuzz;
|
||||
};
|
||||
|
||||
void initialize(int32_t id, const String8& name);
|
||||
|
||||
inline int32_t getId() const { return mId; }
|
||||
inline const String8 getName() const { return mName; }
|
||||
inline uint32_t getSources() const { return mSources; }
|
||||
|
||||
const MotionRange* getMotionRange(int32_t axis, uint32_t source) const;
|
||||
|
||||
void addSource(uint32_t source);
|
||||
void addMotionRange(int32_t axis, uint32_t source,
|
||||
float min, float max, float flat, float fuzz);
|
||||
void addMotionRange(const MotionRange& range);
|
||||
|
||||
inline void setKeyboardType(int32_t keyboardType) { mKeyboardType = keyboardType; }
|
||||
inline int32_t getKeyboardType() const { return mKeyboardType; }
|
||||
|
||||
inline void setKeyCharacterMapFile(const String8& value) { mKeyCharacterMapFile = value; }
|
||||
inline const String8& getKeyCharacterMapFile() const { return mKeyCharacterMapFile; }
|
||||
|
||||
inline const Vector<MotionRange>& getMotionRanges() const {
|
||||
return mMotionRanges;
|
||||
}
|
||||
|
||||
private:
|
||||
int32_t mId;
|
||||
String8 mName;
|
||||
uint32_t mSources;
|
||||
int32_t mKeyboardType;
|
||||
String8 mKeyCharacterMapFile;
|
||||
|
||||
Vector<MotionRange> mMotionRanges;
|
||||
};
|
||||
|
||||
/*
|
||||
* Identifies a device.
|
||||
*/
|
||||
struct InputDeviceIdentifier {
|
||||
inline InputDeviceIdentifier() :
|
||||
bus(0), vendor(0), product(0), version(0) {
|
||||
}
|
||||
|
||||
String8 name;
|
||||
String8 location;
|
||||
String8 uniqueId;
|
||||
uint16_t bus;
|
||||
uint16_t vendor;
|
||||
uint16_t product;
|
||||
uint16_t version;
|
||||
};
|
||||
|
||||
/* Types of input device configuration files. */
|
||||
enum InputDeviceConfigurationFileType {
|
||||
INPUT_DEVICE_CONFIGURATION_FILE_TYPE_CONFIGURATION = 0, /* .idc file */
|
||||
INPUT_DEVICE_CONFIGURATION_FILE_TYPE_KEY_LAYOUT = 1, /* .kl file */
|
||||
INPUT_DEVICE_CONFIGURATION_FILE_TYPE_KEY_CHARACTER_MAP = 2, /* .kcm file */
|
||||
};
|
||||
|
||||
/*
|
||||
* Gets the path of an input device configuration file, if one is available.
|
||||
* Considers both system provided and user installed configuration files.
|
||||
*
|
||||
* The device identifier is used to construct several default configuration file
|
||||
* names to try based on the device name, vendor, product, and version.
|
||||
*
|
||||
* Returns an empty string if not found.
|
||||
*/
|
||||
extern String8 getInputDeviceConfigurationFilePathByDeviceIdentifier(
|
||||
const InputDeviceIdentifier& deviceIdentifier,
|
||||
InputDeviceConfigurationFileType type);
|
||||
|
||||
/*
|
||||
* Gets the path of an input device configuration file, if one is available.
|
||||
* Considers both system provided and user installed configuration files.
|
||||
*
|
||||
* The name is case-sensitive and is used to construct the filename to resolve.
|
||||
* All characters except 'a'-'z', 'A'-'Z', '0'-'9', '-', and '_' are replaced by underscores.
|
||||
*
|
||||
* Returns an empty string if not found.
|
||||
*/
|
||||
extern String8 getInputDeviceConfigurationFilePathByName(
|
||||
const String8& name, InputDeviceConfigurationFileType type);
|
||||
|
||||
} // namespace android
|
||||
|
||||
#endif // _UI_INPUT_H
|
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
* Copyright (C) 2011 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#define LOG_TAG "InputApplication"
|
||||
|
||||
#include "InputApplication.h"
|
||||
|
||||
#include <cutils/log.h>
|
||||
|
||||
namespace android {
|
||||
|
||||
// --- InputApplicationHandle ---
|
||||
|
||||
InputApplicationHandle::InputApplicationHandle() :
|
||||
mInfo(NULL) {
|
||||
}
|
||||
|
||||
InputApplicationHandle::~InputApplicationHandle() {
|
||||
delete mInfo;
|
||||
}
|
||||
|
||||
void InputApplicationHandle::releaseInfo() {
|
||||
if (mInfo) {
|
||||
delete mInfo;
|
||||
mInfo = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace android
|
|
@ -0,0 +1,83 @@
|
|||
/*
|
||||
* Copyright (C) 2011 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef _UI_INPUT_APPLICATION_H
|
||||
#define _UI_INPUT_APPLICATION_H
|
||||
|
||||
#include "Input.h"
|
||||
|
||||
#include <utils/RefBase.h>
|
||||
#include <utils/Timers.h>
|
||||
#include <utils/String8.h>
|
||||
|
||||
namespace android {
|
||||
|
||||
/*
|
||||
* Describes the properties of an application that can receive input.
|
||||
*/
|
||||
struct InputApplicationInfo {
|
||||
String8 name;
|
||||
nsecs_t dispatchingTimeout;
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* Handle for an application that can receive input.
|
||||
*
|
||||
* Used by the native input dispatcher as a handle for the window manager objects
|
||||
* that describe an application.
|
||||
*/
|
||||
class InputApplicationHandle : public RefBase {
|
||||
public:
|
||||
inline const InputApplicationInfo* getInfo() const {
|
||||
return mInfo;
|
||||
}
|
||||
|
||||
inline String8 getName() const {
|
||||
return mInfo ? mInfo->name : String8("<invalid>");
|
||||
}
|
||||
|
||||
inline nsecs_t getDispatchingTimeout(nsecs_t defaultValue) const {
|
||||
return mInfo ? mInfo->dispatchingTimeout : defaultValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Requests that the state of this object be updated to reflect
|
||||
* the most current available information about the application.
|
||||
*
|
||||
* This method should only be called from within the input dispatcher's
|
||||
* critical section.
|
||||
*
|
||||
* Returns true on success, or false if the handle is no longer valid.
|
||||
*/
|
||||
virtual bool updateInfo() = 0;
|
||||
|
||||
/**
|
||||
* Releases the storage used by the associated information when it is
|
||||
* no longer needed.
|
||||
*/
|
||||
void releaseInfo();
|
||||
|
||||
protected:
|
||||
InputApplicationHandle();
|
||||
virtual ~InputApplicationHandle();
|
||||
|
||||
InputApplicationInfo* mInfo;
|
||||
};
|
||||
|
||||
} // namespace android
|
||||
|
||||
#endif // _UI_INPUT_APPLICATION_H
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -0,0 +1,181 @@
|
|||
/*
|
||||
* Copyright (C) 2011 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#define LOG_TAG "InputListener"
|
||||
|
||||
//#define LOG_NDEBUG 0
|
||||
|
||||
#include "InputListener.h"
|
||||
|
||||
#include <cutils/log.h>
|
||||
|
||||
namespace android {
|
||||
|
||||
// --- NotifyConfigurationChangedArgs ---
|
||||
|
||||
NotifyConfigurationChangedArgs::NotifyConfigurationChangedArgs(nsecs_t eventTime) :
|
||||
eventTime(eventTime) {
|
||||
}
|
||||
|
||||
NotifyConfigurationChangedArgs::NotifyConfigurationChangedArgs(
|
||||
const NotifyConfigurationChangedArgs& other) :
|
||||
eventTime(other.eventTime) {
|
||||
}
|
||||
|
||||
void NotifyConfigurationChangedArgs::notify(const sp<InputListenerInterface>& listener) const {
|
||||
listener->notifyConfigurationChanged(this);
|
||||
}
|
||||
|
||||
|
||||
// --- NotifyKeyArgs ---
|
||||
|
||||
NotifyKeyArgs::NotifyKeyArgs(nsecs_t eventTime, int32_t deviceId, uint32_t source,
|
||||
uint32_t policyFlags,
|
||||
int32_t action, int32_t flags, int32_t keyCode, int32_t scanCode,
|
||||
int32_t metaState, nsecs_t downTime) :
|
||||
eventTime(eventTime), deviceId(deviceId), source(source), policyFlags(policyFlags),
|
||||
action(action), flags(flags), keyCode(keyCode), scanCode(scanCode),
|
||||
metaState(metaState), downTime(downTime) {
|
||||
}
|
||||
|
||||
NotifyKeyArgs::NotifyKeyArgs(const NotifyKeyArgs& other) :
|
||||
eventTime(other.eventTime), deviceId(other.deviceId), source(other.source),
|
||||
policyFlags(other.policyFlags),
|
||||
action(other.action), flags(other.flags),
|
||||
keyCode(other.keyCode), scanCode(other.scanCode),
|
||||
metaState(other.metaState), downTime(other.downTime) {
|
||||
}
|
||||
|
||||
void NotifyKeyArgs::notify(const sp<InputListenerInterface>& listener) const {
|
||||
listener->notifyKey(this);
|
||||
}
|
||||
|
||||
|
||||
// --- NotifyMotionArgs ---
|
||||
|
||||
NotifyMotionArgs::NotifyMotionArgs(nsecs_t eventTime, int32_t deviceId, uint32_t source,
|
||||
uint32_t policyFlags,
|
||||
int32_t action, int32_t flags, int32_t metaState, int32_t buttonState,
|
||||
int32_t edgeFlags, uint32_t pointerCount,
|
||||
const PointerProperties* pointerProperties, const PointerCoords* pointerCoords,
|
||||
float xPrecision, float yPrecision, nsecs_t downTime) :
|
||||
eventTime(eventTime), deviceId(deviceId), source(source), policyFlags(policyFlags),
|
||||
action(action), flags(flags), metaState(metaState), buttonState(buttonState),
|
||||
edgeFlags(edgeFlags), pointerCount(pointerCount),
|
||||
xPrecision(xPrecision), yPrecision(yPrecision), downTime(downTime) {
|
||||
for (uint32_t i = 0; i < pointerCount; i++) {
|
||||
this->pointerProperties[i].copyFrom(pointerProperties[i]);
|
||||
this->pointerCoords[i].copyFrom(pointerCoords[i]);
|
||||
}
|
||||
}
|
||||
|
||||
NotifyMotionArgs::NotifyMotionArgs(const NotifyMotionArgs& other) :
|
||||
eventTime(other.eventTime), deviceId(other.deviceId), source(other.source),
|
||||
policyFlags(other.policyFlags),
|
||||
action(other.action), flags(other.flags),
|
||||
metaState(other.metaState), buttonState(other.buttonState),
|
||||
edgeFlags(other.edgeFlags), pointerCount(other.pointerCount),
|
||||
xPrecision(other.xPrecision), yPrecision(other.yPrecision), downTime(other.downTime) {
|
||||
for (uint32_t i = 0; i < pointerCount; i++) {
|
||||
pointerProperties[i].copyFrom(other.pointerProperties[i]);
|
||||
pointerCoords[i].copyFrom(other.pointerCoords[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void NotifyMotionArgs::notify(const sp<InputListenerInterface>& listener) const {
|
||||
listener->notifyMotion(this);
|
||||
}
|
||||
|
||||
|
||||
// --- NotifySwitchArgs ---
|
||||
|
||||
NotifySwitchArgs::NotifySwitchArgs(nsecs_t eventTime, uint32_t policyFlags,
|
||||
int32_t switchCode, int32_t switchValue) :
|
||||
eventTime(eventTime), policyFlags(policyFlags),
|
||||
switchCode(switchCode), switchValue(switchValue) {
|
||||
}
|
||||
|
||||
NotifySwitchArgs::NotifySwitchArgs(const NotifySwitchArgs& other) :
|
||||
eventTime(other.eventTime), policyFlags(other.policyFlags),
|
||||
switchCode(other.switchCode), switchValue(other.switchValue) {
|
||||
}
|
||||
|
||||
void NotifySwitchArgs::notify(const sp<InputListenerInterface>& listener) const {
|
||||
listener->notifySwitch(this);
|
||||
}
|
||||
|
||||
|
||||
// --- NotifyDeviceResetArgs ---
|
||||
|
||||
NotifyDeviceResetArgs::NotifyDeviceResetArgs(nsecs_t eventTime, int32_t deviceId) :
|
||||
eventTime(eventTime), deviceId(deviceId) {
|
||||
}
|
||||
|
||||
NotifyDeviceResetArgs::NotifyDeviceResetArgs(const NotifyDeviceResetArgs& other) :
|
||||
eventTime(other.eventTime), deviceId(other.deviceId) {
|
||||
}
|
||||
|
||||
void NotifyDeviceResetArgs::notify(const sp<InputListenerInterface>& listener) const {
|
||||
listener->notifyDeviceReset(this);
|
||||
}
|
||||
|
||||
|
||||
// --- QueuedInputListener ---
|
||||
|
||||
QueuedInputListener::QueuedInputListener(const sp<InputListenerInterface>& innerListener) :
|
||||
mInnerListener(innerListener) {
|
||||
}
|
||||
|
||||
QueuedInputListener::~QueuedInputListener() {
|
||||
size_t count = mArgsQueue.size();
|
||||
for (size_t i = 0; i < count; i++) {
|
||||
delete mArgsQueue[i];
|
||||
}
|
||||
}
|
||||
|
||||
void QueuedInputListener::notifyConfigurationChanged(
|
||||
const NotifyConfigurationChangedArgs* args) {
|
||||
mArgsQueue.push(new NotifyConfigurationChangedArgs(*args));
|
||||
}
|
||||
|
||||
void QueuedInputListener::notifyKey(const NotifyKeyArgs* args) {
|
||||
mArgsQueue.push(new NotifyKeyArgs(*args));
|
||||
}
|
||||
|
||||
void QueuedInputListener::notifyMotion(const NotifyMotionArgs* args) {
|
||||
mArgsQueue.push(new NotifyMotionArgs(*args));
|
||||
}
|
||||
|
||||
void QueuedInputListener::notifySwitch(const NotifySwitchArgs* args) {
|
||||
mArgsQueue.push(new NotifySwitchArgs(*args));
|
||||
}
|
||||
|
||||
void QueuedInputListener::notifyDeviceReset(const NotifyDeviceResetArgs* args) {
|
||||
mArgsQueue.push(new NotifyDeviceResetArgs(*args));
|
||||
}
|
||||
|
||||
void QueuedInputListener::flush() {
|
||||
size_t count = mArgsQueue.size();
|
||||
for (size_t i = 0; i < count; i++) {
|
||||
NotifyArgs* args = mArgsQueue[i];
|
||||
args->notify(mInnerListener);
|
||||
delete args;
|
||||
}
|
||||
mArgsQueue.clear();
|
||||
}
|
||||
|
||||
|
||||
} // namespace android
|
|
@ -0,0 +1,195 @@
|
|||
/*
|
||||
* Copyright (C) 2011 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef _UI_INPUT_LISTENER_H
|
||||
#define _UI_INPUT_LISTENER_H
|
||||
|
||||
#include "Input.h"
|
||||
#include <utils/RefBase.h>
|
||||
#include <utils/Vector.h>
|
||||
|
||||
namespace android {
|
||||
|
||||
class InputListenerInterface;
|
||||
|
||||
|
||||
/* Superclass of all input event argument objects */
|
||||
struct NotifyArgs {
|
||||
virtual ~NotifyArgs() { }
|
||||
|
||||
virtual void notify(const sp<InputListenerInterface>& listener) const = 0;
|
||||
};
|
||||
|
||||
|
||||
/* Describes a configuration change event. */
|
||||
struct NotifyConfigurationChangedArgs : public NotifyArgs {
|
||||
nsecs_t eventTime;
|
||||
|
||||
inline NotifyConfigurationChangedArgs() { }
|
||||
|
||||
NotifyConfigurationChangedArgs(nsecs_t eventTime);
|
||||
|
||||
NotifyConfigurationChangedArgs(const NotifyConfigurationChangedArgs& other);
|
||||
|
||||
virtual ~NotifyConfigurationChangedArgs() { }
|
||||
|
||||
virtual void notify(const sp<InputListenerInterface>& listener) const;
|
||||
};
|
||||
|
||||
|
||||
/* Describes a key event. */
|
||||
struct NotifyKeyArgs : public NotifyArgs {
|
||||
nsecs_t eventTime;
|
||||
int32_t deviceId;
|
||||
uint32_t source;
|
||||
uint32_t policyFlags;
|
||||
int32_t action;
|
||||
int32_t flags;
|
||||
int32_t keyCode;
|
||||
int32_t scanCode;
|
||||
int32_t metaState;
|
||||
nsecs_t downTime;
|
||||
|
||||
inline NotifyKeyArgs() { }
|
||||
|
||||
NotifyKeyArgs(nsecs_t eventTime, int32_t deviceId, uint32_t source, uint32_t policyFlags,
|
||||
int32_t action, int32_t flags, int32_t keyCode, int32_t scanCode,
|
||||
int32_t metaState, nsecs_t downTime);
|
||||
|
||||
NotifyKeyArgs(const NotifyKeyArgs& other);
|
||||
|
||||
virtual ~NotifyKeyArgs() { }
|
||||
|
||||
virtual void notify(const sp<InputListenerInterface>& listener) const;
|
||||
};
|
||||
|
||||
|
||||
/* Describes a motion event. */
|
||||
struct NotifyMotionArgs : public NotifyArgs {
|
||||
nsecs_t eventTime;
|
||||
int32_t deviceId;
|
||||
uint32_t source;
|
||||
uint32_t policyFlags;
|
||||
int32_t action;
|
||||
int32_t flags;
|
||||
int32_t metaState;
|
||||
int32_t buttonState;
|
||||
int32_t edgeFlags;
|
||||
uint32_t pointerCount;
|
||||
PointerProperties pointerProperties[MAX_POINTERS];
|
||||
PointerCoords pointerCoords[MAX_POINTERS];
|
||||
float xPrecision;
|
||||
float yPrecision;
|
||||
nsecs_t downTime;
|
||||
|
||||
inline NotifyMotionArgs() { }
|
||||
|
||||
NotifyMotionArgs(nsecs_t eventTime, int32_t deviceId, uint32_t source, uint32_t policyFlags,
|
||||
int32_t action, int32_t flags, int32_t metaState, int32_t buttonState,
|
||||
int32_t edgeFlags, uint32_t pointerCount,
|
||||
const PointerProperties* pointerProperties, const PointerCoords* pointerCoords,
|
||||
float xPrecision, float yPrecision, nsecs_t downTime);
|
||||
|
||||
NotifyMotionArgs(const NotifyMotionArgs& other);
|
||||
|
||||
virtual ~NotifyMotionArgs() { }
|
||||
|
||||
virtual void notify(const sp<InputListenerInterface>& listener) const;
|
||||
};
|
||||
|
||||
|
||||
/* Describes a switch event. */
|
||||
struct NotifySwitchArgs : public NotifyArgs {
|
||||
nsecs_t eventTime;
|
||||
uint32_t policyFlags;
|
||||
int32_t switchCode;
|
||||
int32_t switchValue;
|
||||
|
||||
inline NotifySwitchArgs() { }
|
||||
|
||||
NotifySwitchArgs(nsecs_t eventTime, uint32_t policyFlags,
|
||||
int32_t switchCode, int32_t switchValue);
|
||||
|
||||
NotifySwitchArgs(const NotifySwitchArgs& other);
|
||||
|
||||
virtual ~NotifySwitchArgs() { }
|
||||
|
||||
virtual void notify(const sp<InputListenerInterface>& listener) const;
|
||||
};
|
||||
|
||||
|
||||
/* Describes a device reset event, such as when a device is added,
|
||||
* reconfigured, or removed. */
|
||||
struct NotifyDeviceResetArgs : public NotifyArgs {
|
||||
nsecs_t eventTime;
|
||||
int32_t deviceId;
|
||||
|
||||
inline NotifyDeviceResetArgs() { }
|
||||
|
||||
NotifyDeviceResetArgs(nsecs_t eventTime, int32_t deviceId);
|
||||
|
||||
NotifyDeviceResetArgs(const NotifyDeviceResetArgs& other);
|
||||
|
||||
virtual ~NotifyDeviceResetArgs() { }
|
||||
|
||||
virtual void notify(const sp<InputListenerInterface>& listener) const;
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* The interface used by the InputReader to notify the InputListener about input events.
|
||||
*/
|
||||
class InputListenerInterface : public virtual RefBase {
|
||||
protected:
|
||||
InputListenerInterface() { }
|
||||
virtual ~InputListenerInterface() { }
|
||||
|
||||
public:
|
||||
virtual void notifyConfigurationChanged(const NotifyConfigurationChangedArgs* args) = 0;
|
||||
virtual void notifyKey(const NotifyKeyArgs* args) = 0;
|
||||
virtual void notifyMotion(const NotifyMotionArgs* args) = 0;
|
||||
virtual void notifySwitch(const NotifySwitchArgs* args) = 0;
|
||||
virtual void notifyDeviceReset(const NotifyDeviceResetArgs* args) = 0;
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* An implementation of the listener interface that queues up and defers dispatch
|
||||
* of decoded events until flushed.
|
||||
*/
|
||||
class QueuedInputListener : public InputListenerInterface {
|
||||
protected:
|
||||
virtual ~QueuedInputListener();
|
||||
|
||||
public:
|
||||
QueuedInputListener(const sp<InputListenerInterface>& innerListener);
|
||||
|
||||
virtual void notifyConfigurationChanged(const NotifyConfigurationChangedArgs* args);
|
||||
virtual void notifyKey(const NotifyKeyArgs* args);
|
||||
virtual void notifyMotion(const NotifyMotionArgs* args);
|
||||
virtual void notifySwitch(const NotifySwitchArgs* args);
|
||||
virtual void notifyDeviceReset(const NotifyDeviceResetArgs* args);
|
||||
|
||||
void flush();
|
||||
|
||||
private:
|
||||
sp<InputListenerInterface> mInnerListener;
|
||||
Vector<NotifyArgs*> mArgsQueue;
|
||||
};
|
||||
|
||||
} // namespace android
|
||||
|
||||
#endif // _UI_INPUT_LISTENER_H
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -0,0 +1,727 @@
|
|||
//
|
||||
// Copyright 2010 The Android Open Source Project
|
||||
//
|
||||
// Provides a shared memory transport for input events.
|
||||
//
|
||||
#define LOG_TAG "InputTransport"
|
||||
|
||||
//#define LOG_NDEBUG 0
|
||||
|
||||
// Log debug messages about channel signalling (send signal, receive signal)
|
||||
#define DEBUG_CHANNEL_SIGNALS 0
|
||||
|
||||
// Log debug messages whenever InputChannel objects are created/destroyed
|
||||
#define DEBUG_CHANNEL_LIFECYCLE 0
|
||||
|
||||
// Log debug messages about transport actions (initialize, reset, publish, ...)
|
||||
#define DEBUG_TRANSPORT_ACTIONS 0
|
||||
|
||||
|
||||
#include <cutils/ashmem.h>
|
||||
#include <cutils/log.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/mman.h>
|
||||
#include "InputTransport.h"
|
||||
#include <unistd.h>
|
||||
|
||||
namespace android {
|
||||
|
||||
#define ROUND_UP(value, boundary) (((value) + (boundary) - 1) & ~((boundary) - 1))
|
||||
#define MIN_HISTORY_DEPTH 20
|
||||
|
||||
// Must be at least sizeof(InputMessage) + sufficient space for pointer data
|
||||
static const int DEFAULT_MESSAGE_BUFFER_SIZE = ROUND_UP(
|
||||
sizeof(InputMessage) + MIN_HISTORY_DEPTH
|
||||
* (sizeof(InputMessage::SampleData) + MAX_POINTERS * sizeof(PointerCoords)),
|
||||
4096);
|
||||
|
||||
// Signal sent by the producer to the consumer to inform it that a new message is
|
||||
// available to be consumed in the shared memory buffer.
|
||||
static const char INPUT_SIGNAL_DISPATCH = 'D';
|
||||
|
||||
// Signal sent by the consumer to the producer to inform it that it has finished
|
||||
// consuming the most recent message and it handled it.
|
||||
static const char INPUT_SIGNAL_FINISHED_HANDLED = 'f';
|
||||
|
||||
// Signal sent by the consumer to the producer to inform it that it has finished
|
||||
// consuming the most recent message but it did not handle it.
|
||||
static const char INPUT_SIGNAL_FINISHED_UNHANDLED = 'u';
|
||||
|
||||
|
||||
// --- InputChannel ---
|
||||
|
||||
InputChannel::InputChannel(const String8& name, int32_t ashmemFd, int32_t receivePipeFd,
|
||||
int32_t sendPipeFd) :
|
||||
mName(name), mAshmemFd(ashmemFd), mReceivePipeFd(receivePipeFd), mSendPipeFd(sendPipeFd) {
|
||||
#if DEBUG_CHANNEL_LIFECYCLE
|
||||
ALOGD("Input channel constructed: name='%s', ashmemFd=%d, receivePipeFd=%d, sendPipeFd=%d",
|
||||
mName.string(), ashmemFd, receivePipeFd, sendPipeFd);
|
||||
#endif
|
||||
|
||||
int result = fcntl(mReceivePipeFd, F_SETFL, O_NONBLOCK);
|
||||
LOG_ALWAYS_FATAL_IF(result != 0, "channel '%s' ~ Could not make receive pipe "
|
||||
"non-blocking. errno=%d", mName.string(), errno);
|
||||
|
||||
result = fcntl(mSendPipeFd, F_SETFL, O_NONBLOCK);
|
||||
LOG_ALWAYS_FATAL_IF(result != 0, "channel '%s' ~ Could not make send pipe "
|
||||
"non-blocking. errno=%d", mName.string(), errno);
|
||||
}
|
||||
|
||||
InputChannel::~InputChannel() {
|
||||
#if DEBUG_CHANNEL_LIFECYCLE
|
||||
ALOGD("Input channel destroyed: name='%s', ashmemFd=%d, receivePipeFd=%d, sendPipeFd=%d",
|
||||
mName.string(), mAshmemFd, mReceivePipeFd, mSendPipeFd);
|
||||
#endif
|
||||
|
||||
::close(mAshmemFd);
|
||||
::close(mReceivePipeFd);
|
||||
::close(mSendPipeFd);
|
||||
}
|
||||
|
||||
status_t InputChannel::openInputChannelPair(const String8& name,
|
||||
sp<InputChannel>& outServerChannel, sp<InputChannel>& outClientChannel) {
|
||||
status_t result;
|
||||
|
||||
String8 ashmemName("InputChannel ");
|
||||
ashmemName.append(name);
|
||||
int serverAshmemFd = ashmem_create_region(ashmemName.string(), DEFAULT_MESSAGE_BUFFER_SIZE);
|
||||
if (serverAshmemFd < 0) {
|
||||
result = -errno;
|
||||
ALOGE("channel '%s' ~ Could not create shared memory region. errno=%d",
|
||||
name.string(), errno);
|
||||
} else {
|
||||
result = ashmem_set_prot_region(serverAshmemFd, PROT_READ | PROT_WRITE);
|
||||
if (result < 0) {
|
||||
ALOGE("channel '%s' ~ Error %d trying to set protection of ashmem fd %d.",
|
||||
name.string(), result, serverAshmemFd);
|
||||
} else {
|
||||
// Dup the file descriptor because the server and client input channel objects that
|
||||
// are returned may have different lifetimes but they share the same shared memory region.
|
||||
int clientAshmemFd;
|
||||
clientAshmemFd = dup(serverAshmemFd);
|
||||
if (clientAshmemFd < 0) {
|
||||
result = -errno;
|
||||
ALOGE("channel '%s' ~ Could not dup() shared memory region fd. errno=%d",
|
||||
name.string(), errno);
|
||||
} else {
|
||||
int forward[2];
|
||||
if (pipe(forward)) {
|
||||
result = -errno;
|
||||
ALOGE("channel '%s' ~ Could not create forward pipe. errno=%d",
|
||||
name.string(), errno);
|
||||
} else {
|
||||
int reverse[2];
|
||||
if (pipe(reverse)) {
|
||||
result = -errno;
|
||||
ALOGE("channel '%s' ~ Could not create reverse pipe. errno=%d",
|
||||
name.string(), errno);
|
||||
} else {
|
||||
String8 serverChannelName = name;
|
||||
serverChannelName.append(" (server)");
|
||||
outServerChannel = new InputChannel(serverChannelName,
|
||||
serverAshmemFd, reverse[0], forward[1]);
|
||||
|
||||
String8 clientChannelName = name;
|
||||
clientChannelName.append(" (client)");
|
||||
outClientChannel = new InputChannel(clientChannelName,
|
||||
clientAshmemFd, forward[0], reverse[1]);
|
||||
return OK;
|
||||
}
|
||||
::close(forward[0]);
|
||||
::close(forward[1]);
|
||||
}
|
||||
::close(clientAshmemFd);
|
||||
}
|
||||
}
|
||||
::close(serverAshmemFd);
|
||||
}
|
||||
|
||||
outServerChannel.clear();
|
||||
outClientChannel.clear();
|
||||
return result;
|
||||
}
|
||||
|
||||
status_t InputChannel::sendSignal(char signal) {
|
||||
ssize_t nWrite;
|
||||
do {
|
||||
nWrite = ::write(mSendPipeFd, & signal, 1);
|
||||
} while (nWrite == -1 && errno == EINTR);
|
||||
|
||||
if (nWrite == 1) {
|
||||
#if DEBUG_CHANNEL_SIGNALS
|
||||
ALOGD("channel '%s' ~ sent signal '%c'", mName.string(), signal);
|
||||
#endif
|
||||
return OK;
|
||||
}
|
||||
|
||||
#if DEBUG_CHANNEL_SIGNALS
|
||||
ALOGD("channel '%s' ~ error sending signal '%c', errno=%d", mName.string(), signal, errno);
|
||||
#endif
|
||||
return -errno;
|
||||
}
|
||||
|
||||
status_t InputChannel::receiveSignal(char* outSignal) {
|
||||
ssize_t nRead;
|
||||
do {
|
||||
nRead = ::read(mReceivePipeFd, outSignal, 1);
|
||||
} while (nRead == -1 && errno == EINTR);
|
||||
|
||||
if (nRead == 1) {
|
||||
#if DEBUG_CHANNEL_SIGNALS
|
||||
ALOGD("channel '%s' ~ received signal '%c'", mName.string(), *outSignal);
|
||||
#endif
|
||||
return OK;
|
||||
}
|
||||
|
||||
if (nRead == 0) { // check for EOF
|
||||
#if DEBUG_CHANNEL_SIGNALS
|
||||
ALOGD("channel '%s' ~ receive signal failed because peer was closed", mName.string());
|
||||
#endif
|
||||
return DEAD_OBJECT;
|
||||
}
|
||||
|
||||
if (errno == EAGAIN) {
|
||||
#if DEBUG_CHANNEL_SIGNALS
|
||||
ALOGD("channel '%s' ~ receive signal failed because no signal available", mName.string());
|
||||
#endif
|
||||
return WOULD_BLOCK;
|
||||
}
|
||||
|
||||
#if DEBUG_CHANNEL_SIGNALS
|
||||
ALOGD("channel '%s' ~ receive signal failed, errno=%d", mName.string(), errno);
|
||||
#endif
|
||||
return -errno;
|
||||
}
|
||||
|
||||
|
||||
// --- InputPublisher ---
|
||||
|
||||
InputPublisher::InputPublisher(const sp<InputChannel>& channel) :
|
||||
mChannel(channel), mSharedMessage(NULL),
|
||||
mPinned(false), mSemaphoreInitialized(false), mWasDispatched(false),
|
||||
mMotionEventSampleDataTail(NULL) {
|
||||
}
|
||||
|
||||
InputPublisher::~InputPublisher() {
|
||||
reset();
|
||||
|
||||
if (mSharedMessage) {
|
||||
munmap(mSharedMessage, mAshmemSize);
|
||||
}
|
||||
}
|
||||
|
||||
status_t InputPublisher::initialize() {
|
||||
#if DEBUG_TRANSPORT_ACTIONS
|
||||
ALOGD("channel '%s' publisher ~ initialize",
|
||||
mChannel->getName().string());
|
||||
#endif
|
||||
|
||||
int ashmemFd = mChannel->getAshmemFd();
|
||||
int result = ashmem_get_size_region(ashmemFd);
|
||||
if (result < 0) {
|
||||
ALOGE("channel '%s' publisher ~ Error %d getting size of ashmem fd %d.",
|
||||
mChannel->getName().string(), result, ashmemFd);
|
||||
return UNKNOWN_ERROR;
|
||||
}
|
||||
mAshmemSize = (size_t) result;
|
||||
|
||||
mSharedMessage = static_cast<InputMessage*>(mmap(NULL, mAshmemSize,
|
||||
PROT_READ | PROT_WRITE, MAP_SHARED, ashmemFd, 0));
|
||||
if (! mSharedMessage) {
|
||||
ALOGE("channel '%s' publisher ~ mmap failed on ashmem fd %d.",
|
||||
mChannel->getName().string(), ashmemFd);
|
||||
return NO_MEMORY;
|
||||
}
|
||||
|
||||
mPinned = true;
|
||||
mSharedMessage->consumed = false;
|
||||
|
||||
return reset();
|
||||
}
|
||||
|
||||
status_t InputPublisher::reset() {
|
||||
#if DEBUG_TRANSPORT_ACTIONS
|
||||
ALOGD("channel '%s' publisher ~ reset",
|
||||
mChannel->getName().string());
|
||||
#endif
|
||||
|
||||
if (mPinned) {
|
||||
// Destroy the semaphore since we are about to unpin the memory region that contains it.
|
||||
int result;
|
||||
if (mSemaphoreInitialized) {
|
||||
if (mSharedMessage->consumed) {
|
||||
result = sem_post(& mSharedMessage->semaphore);
|
||||
if (result < 0) {
|
||||
ALOGE("channel '%s' publisher ~ Error %d in sem_post.",
|
||||
mChannel->getName().string(), errno);
|
||||
return UNKNOWN_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
result = sem_destroy(& mSharedMessage->semaphore);
|
||||
if (result < 0) {
|
||||
ALOGE("channel '%s' publisher ~ Error %d in sem_destroy.",
|
||||
mChannel->getName().string(), errno);
|
||||
return UNKNOWN_ERROR;
|
||||
}
|
||||
|
||||
mSemaphoreInitialized = false;
|
||||
}
|
||||
|
||||
// Unpin the region since we no longer care about its contents.
|
||||
int ashmemFd = mChannel->getAshmemFd();
|
||||
result = ashmem_unpin_region(ashmemFd, 0, 0);
|
||||
if (result < 0) {
|
||||
ALOGE("channel '%s' publisher ~ Error %d unpinning ashmem fd %d.",
|
||||
mChannel->getName().string(), result, ashmemFd);
|
||||
return UNKNOWN_ERROR;
|
||||
}
|
||||
|
||||
mPinned = false;
|
||||
}
|
||||
|
||||
mMotionEventSampleDataTail = NULL;
|
||||
mWasDispatched = false;
|
||||
return OK;
|
||||
}
|
||||
|
||||
status_t InputPublisher::publishInputEvent(
|
||||
int32_t type,
|
||||
int32_t deviceId,
|
||||
int32_t source) {
|
||||
if (mPinned) {
|
||||
ALOGE("channel '%s' publisher ~ Attempted to publish a new event but publisher has "
|
||||
"not yet been reset.", mChannel->getName().string());
|
||||
return INVALID_OPERATION;
|
||||
}
|
||||
|
||||
// Pin the region.
|
||||
// We do not check for ASHMEM_NOT_PURGED because we don't care about the previous
|
||||
// contents of the buffer so it does not matter whether it was purged in the meantime.
|
||||
int ashmemFd = mChannel->getAshmemFd();
|
||||
int result = ashmem_pin_region(ashmemFd, 0, 0);
|
||||
if (result < 0) {
|
||||
ALOGE("channel '%s' publisher ~ Error %d pinning ashmem fd %d.",
|
||||
mChannel->getName().string(), result, ashmemFd);
|
||||
return UNKNOWN_ERROR;
|
||||
}
|
||||
|
||||
mPinned = true;
|
||||
|
||||
result = sem_init(& mSharedMessage->semaphore, 1, 1);
|
||||
if (result < 0) {
|
||||
ALOGE("channel '%s' publisher ~ Error %d in sem_init.",
|
||||
mChannel->getName().string(), errno);
|
||||
return UNKNOWN_ERROR;
|
||||
}
|
||||
|
||||
mSemaphoreInitialized = true;
|
||||
|
||||
mSharedMessage->consumed = false;
|
||||
mSharedMessage->type = type;
|
||||
mSharedMessage->deviceId = deviceId;
|
||||
mSharedMessage->source = source;
|
||||
return OK;
|
||||
}
|
||||
|
||||
status_t InputPublisher::publishKeyEvent(
|
||||
int32_t deviceId,
|
||||
int32_t source,
|
||||
int32_t action,
|
||||
int32_t flags,
|
||||
int32_t keyCode,
|
||||
int32_t scanCode,
|
||||
int32_t metaState,
|
||||
int32_t repeatCount,
|
||||
nsecs_t downTime,
|
||||
nsecs_t eventTime) {
|
||||
#if DEBUG_TRANSPORT_ACTIONS
|
||||
ALOGD("channel '%s' publisher ~ publishKeyEvent: deviceId=%d, source=0x%x, "
|
||||
"action=0x%x, flags=0x%x, keyCode=%d, scanCode=%d, metaState=0x%x, repeatCount=%d,"
|
||||
"downTime=%lld, eventTime=%lld",
|
||||
mChannel->getName().string(),
|
||||
deviceId, source, action, flags, keyCode, scanCode, metaState, repeatCount,
|
||||
downTime, eventTime);
|
||||
#endif
|
||||
|
||||
status_t result = publishInputEvent(AINPUT_EVENT_TYPE_KEY, deviceId, source);
|
||||
if (result < 0) {
|
||||
return result;
|
||||
}
|
||||
|
||||
mSharedMessage->key.action = action;
|
||||
mSharedMessage->key.flags = flags;
|
||||
mSharedMessage->key.keyCode = keyCode;
|
||||
mSharedMessage->key.scanCode = scanCode;
|
||||
mSharedMessage->key.metaState = metaState;
|
||||
mSharedMessage->key.repeatCount = repeatCount;
|
||||
mSharedMessage->key.downTime = downTime;
|
||||
mSharedMessage->key.eventTime = eventTime;
|
||||
return OK;
|
||||
}
|
||||
|
||||
status_t InputPublisher::publishMotionEvent(
|
||||
int32_t deviceId,
|
||||
int32_t source,
|
||||
int32_t action,
|
||||
int32_t flags,
|
||||
int32_t edgeFlags,
|
||||
int32_t metaState,
|
||||
int32_t buttonState,
|
||||
float xOffset,
|
||||
float yOffset,
|
||||
float xPrecision,
|
||||
float yPrecision,
|
||||
nsecs_t downTime,
|
||||
nsecs_t eventTime,
|
||||
size_t pointerCount,
|
||||
const PointerProperties* pointerProperties,
|
||||
const PointerCoords* pointerCoords) {
|
||||
#if DEBUG_TRANSPORT_ACTIONS
|
||||
ALOGD("channel '%s' publisher ~ publishMotionEvent: deviceId=%d, source=0x%x, "
|
||||
"action=0x%x, flags=0x%x, edgeFlags=0x%x, metaState=0x%x, buttonState=0x%x, "
|
||||
"xOffset=%f, yOffset=%f, "
|
||||
"xPrecision=%f, yPrecision=%f, downTime=%lld, eventTime=%lld, "
|
||||
"pointerCount=%d",
|
||||
mChannel->getName().string(),
|
||||
deviceId, source, action, flags, edgeFlags, metaState, buttonState,
|
||||
xOffset, yOffset, xPrecision, yPrecision, downTime, eventTime, pointerCount);
|
||||
#endif
|
||||
|
||||
if (pointerCount > MAX_POINTERS || pointerCount < 1) {
|
||||
ALOGE("channel '%s' publisher ~ Invalid number of pointers provided: %d.",
|
||||
mChannel->getName().string(), pointerCount);
|
||||
return BAD_VALUE;
|
||||
}
|
||||
|
||||
status_t result = publishInputEvent(AINPUT_EVENT_TYPE_MOTION, deviceId, source);
|
||||
if (result < 0) {
|
||||
return result;
|
||||
}
|
||||
|
||||
mSharedMessage->motion.action = action;
|
||||
mSharedMessage->motion.flags = flags;
|
||||
mSharedMessage->motion.edgeFlags = edgeFlags;
|
||||
mSharedMessage->motion.metaState = metaState;
|
||||
mSharedMessage->motion.buttonState = buttonState;
|
||||
mSharedMessage->motion.xOffset = xOffset;
|
||||
mSharedMessage->motion.yOffset = yOffset;
|
||||
mSharedMessage->motion.xPrecision = xPrecision;
|
||||
mSharedMessage->motion.yPrecision = yPrecision;
|
||||
mSharedMessage->motion.downTime = downTime;
|
||||
mSharedMessage->motion.pointerCount = pointerCount;
|
||||
|
||||
mSharedMessage->motion.sampleCount = 1;
|
||||
mSharedMessage->motion.sampleData[0].eventTime = eventTime;
|
||||
|
||||
for (size_t i = 0; i < pointerCount; i++) {
|
||||
mSharedMessage->motion.pointerProperties[i].copyFrom(pointerProperties[i]);
|
||||
mSharedMessage->motion.sampleData[0].coords[i].copyFrom(pointerCoords[i]);
|
||||
}
|
||||
|
||||
// Cache essential information about the motion event to ensure that a malicious consumer
|
||||
// cannot confuse the publisher by modifying the contents of the shared memory buffer while
|
||||
// it is being updated.
|
||||
if (action == AMOTION_EVENT_ACTION_MOVE
|
||||
|| action == AMOTION_EVENT_ACTION_HOVER_MOVE) {
|
||||
mMotionEventPointerCount = pointerCount;
|
||||
mMotionEventSampleDataStride = InputMessage::sampleDataStride(pointerCount);
|
||||
mMotionEventSampleDataTail = InputMessage::sampleDataPtrIncrement(
|
||||
mSharedMessage->motion.sampleData, mMotionEventSampleDataStride);
|
||||
} else {
|
||||
mMotionEventSampleDataTail = NULL;
|
||||
}
|
||||
return OK;
|
||||
}
|
||||
|
||||
status_t InputPublisher::appendMotionSample(
|
||||
nsecs_t eventTime,
|
||||
const PointerCoords* pointerCoords) {
|
||||
#if DEBUG_TRANSPORT_ACTIONS
|
||||
ALOGD("channel '%s' publisher ~ appendMotionSample: eventTime=%lld",
|
||||
mChannel->getName().string(), eventTime);
|
||||
#endif
|
||||
|
||||
if (! mPinned || ! mMotionEventSampleDataTail) {
|
||||
ALOGE("channel '%s' publisher ~ Cannot append motion sample because there is no current "
|
||||
"AMOTION_EVENT_ACTION_MOVE or AMOTION_EVENT_ACTION_HOVER_MOVE event.",
|
||||
mChannel->getName().string());
|
||||
return INVALID_OPERATION;
|
||||
}
|
||||
|
||||
InputMessage::SampleData* newTail = InputMessage::sampleDataPtrIncrement(
|
||||
mMotionEventSampleDataTail, mMotionEventSampleDataStride);
|
||||
size_t newBytesUsed = reinterpret_cast<char*>(newTail) -
|
||||
reinterpret_cast<char*>(mSharedMessage);
|
||||
|
||||
if (newBytesUsed > mAshmemSize) {
|
||||
#if DEBUG_TRANSPORT_ACTIONS
|
||||
ALOGD("channel '%s' publisher ~ Cannot append motion sample because the shared memory "
|
||||
"buffer is full. Buffer size: %d bytes, pointers: %d, samples: %d",
|
||||
mChannel->getName().string(),
|
||||
mAshmemSize, mMotionEventPointerCount, mSharedMessage->motion.sampleCount);
|
||||
#endif
|
||||
return NO_MEMORY;
|
||||
}
|
||||
|
||||
int result;
|
||||
if (mWasDispatched) {
|
||||
result = sem_trywait(& mSharedMessage->semaphore);
|
||||
if (result < 0) {
|
||||
if (errno == EAGAIN) {
|
||||
// Only possible source of contention is the consumer having consumed (or being in the
|
||||
// process of consuming) the message and left the semaphore count at 0.
|
||||
#if DEBUG_TRANSPORT_ACTIONS
|
||||
ALOGD("channel '%s' publisher ~ Cannot append motion sample because the message has "
|
||||
"already been consumed.", mChannel->getName().string());
|
||||
#endif
|
||||
return FAILED_TRANSACTION;
|
||||
} else {
|
||||
ALOGE("channel '%s' publisher ~ Error %d in sem_trywait.",
|
||||
mChannel->getName().string(), errno);
|
||||
return UNKNOWN_ERROR;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mMotionEventSampleDataTail->eventTime = eventTime;
|
||||
for (size_t i = 0; i < mMotionEventPointerCount; i++) {
|
||||
mMotionEventSampleDataTail->coords[i].copyFrom(pointerCoords[i]);
|
||||
}
|
||||
mMotionEventSampleDataTail = newTail;
|
||||
|
||||
mSharedMessage->motion.sampleCount += 1;
|
||||
|
||||
if (mWasDispatched) {
|
||||
result = sem_post(& mSharedMessage->semaphore);
|
||||
if (result < 0) {
|
||||
ALOGE("channel '%s' publisher ~ Error %d in sem_post.",
|
||||
mChannel->getName().string(), errno);
|
||||
return UNKNOWN_ERROR;
|
||||
}
|
||||
}
|
||||
return OK;
|
||||
}
|
||||
|
||||
status_t InputPublisher::sendDispatchSignal() {
|
||||
#if DEBUG_TRANSPORT_ACTIONS
|
||||
ALOGD("channel '%s' publisher ~ sendDispatchSignal",
|
||||
mChannel->getName().string());
|
||||
#endif
|
||||
|
||||
mWasDispatched = true;
|
||||
return mChannel->sendSignal(INPUT_SIGNAL_DISPATCH);
|
||||
}
|
||||
|
||||
status_t InputPublisher::receiveFinishedSignal(bool* outHandled) {
|
||||
#if DEBUG_TRANSPORT_ACTIONS
|
||||
ALOGD("channel '%s' publisher ~ receiveFinishedSignal",
|
||||
mChannel->getName().string());
|
||||
#endif
|
||||
|
||||
char signal;
|
||||
status_t result = mChannel->receiveSignal(& signal);
|
||||
if (result) {
|
||||
*outHandled = false;
|
||||
return result;
|
||||
}
|
||||
if (signal == INPUT_SIGNAL_FINISHED_HANDLED) {
|
||||
*outHandled = true;
|
||||
} else if (signal == INPUT_SIGNAL_FINISHED_UNHANDLED) {
|
||||
*outHandled = false;
|
||||
} else {
|
||||
ALOGE("channel '%s' publisher ~ Received unexpected signal '%c' from consumer",
|
||||
mChannel->getName().string(), signal);
|
||||
return UNKNOWN_ERROR;
|
||||
}
|
||||
return OK;
|
||||
}
|
||||
|
||||
// --- InputConsumer ---
|
||||
|
||||
InputConsumer::InputConsumer(const sp<InputChannel>& channel) :
|
||||
mChannel(channel), mSharedMessage(NULL) {
|
||||
}
|
||||
|
||||
InputConsumer::~InputConsumer() {
|
||||
if (mSharedMessage) {
|
||||
munmap(mSharedMessage, mAshmemSize);
|
||||
}
|
||||
}
|
||||
|
||||
status_t InputConsumer::initialize() {
|
||||
#if DEBUG_TRANSPORT_ACTIONS
|
||||
ALOGD("channel '%s' consumer ~ initialize",
|
||||
mChannel->getName().string());
|
||||
#endif
|
||||
|
||||
int ashmemFd = mChannel->getAshmemFd();
|
||||
int result = ashmem_get_size_region(ashmemFd);
|
||||
if (result < 0) {
|
||||
ALOGE("channel '%s' consumer ~ Error %d getting size of ashmem fd %d.",
|
||||
mChannel->getName().string(), result, ashmemFd);
|
||||
return UNKNOWN_ERROR;
|
||||
}
|
||||
|
||||
mAshmemSize = (size_t) result;
|
||||
|
||||
mSharedMessage = static_cast<InputMessage*>(mmap(NULL, mAshmemSize,
|
||||
PROT_READ | PROT_WRITE, MAP_SHARED, ashmemFd, 0));
|
||||
if (! mSharedMessage) {
|
||||
ALOGE("channel '%s' consumer ~ mmap failed on ashmem fd %d.",
|
||||
mChannel->getName().string(), ashmemFd);
|
||||
return NO_MEMORY;
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
status_t InputConsumer::consume(InputEventFactoryInterface* factory, InputEvent** outEvent) {
|
||||
#if DEBUG_TRANSPORT_ACTIONS
|
||||
ALOGD("channel '%s' consumer ~ consume",
|
||||
mChannel->getName().string());
|
||||
#endif
|
||||
|
||||
*outEvent = NULL;
|
||||
|
||||
int ashmemFd = mChannel->getAshmemFd();
|
||||
int result = ashmem_pin_region(ashmemFd, 0, 0);
|
||||
if (result != ASHMEM_NOT_PURGED) {
|
||||
if (result == ASHMEM_WAS_PURGED) {
|
||||
ALOGE("channel '%s' consumer ~ Error %d pinning ashmem fd %d because it was purged "
|
||||
"which probably indicates that the publisher and consumer are out of sync.",
|
||||
mChannel->getName().string(), result, ashmemFd);
|
||||
return INVALID_OPERATION;
|
||||
}
|
||||
|
||||
ALOGE("channel '%s' consumer ~ Error %d pinning ashmem fd %d.",
|
||||
mChannel->getName().string(), result, ashmemFd);
|
||||
return UNKNOWN_ERROR;
|
||||
}
|
||||
|
||||
if (mSharedMessage->consumed) {
|
||||
ALOGE("channel '%s' consumer ~ The current message has already been consumed.",
|
||||
mChannel->getName().string());
|
||||
return INVALID_OPERATION;
|
||||
}
|
||||
|
||||
// Acquire but *never release* the semaphore. Contention on the semaphore is used to signal
|
||||
// to the publisher that the message has been consumed (or is in the process of being
|
||||
// consumed). Eventually the publisher will reinitialize the semaphore for the next message.
|
||||
result = sem_wait(& mSharedMessage->semaphore);
|
||||
if (result < 0) {
|
||||
ALOGE("channel '%s' consumer ~ Error %d in sem_wait.",
|
||||
mChannel->getName().string(), errno);
|
||||
return UNKNOWN_ERROR;
|
||||
}
|
||||
|
||||
mSharedMessage->consumed = true;
|
||||
|
||||
switch (mSharedMessage->type) {
|
||||
case AINPUT_EVENT_TYPE_KEY: {
|
||||
KeyEvent* keyEvent = factory->createKeyEvent();
|
||||
if (! keyEvent) return NO_MEMORY;
|
||||
|
||||
populateKeyEvent(keyEvent);
|
||||
|
||||
*outEvent = keyEvent;
|
||||
break;
|
||||
}
|
||||
|
||||
case AINPUT_EVENT_TYPE_MOTION: {
|
||||
MotionEvent* motionEvent = factory->createMotionEvent();
|
||||
if (! motionEvent) return NO_MEMORY;
|
||||
|
||||
populateMotionEvent(motionEvent);
|
||||
|
||||
*outEvent = motionEvent;
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
ALOGE("channel '%s' consumer ~ Received message of unknown type %d",
|
||||
mChannel->getName().string(), mSharedMessage->type);
|
||||
return UNKNOWN_ERROR;
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
status_t InputConsumer::sendFinishedSignal(bool handled) {
|
||||
#if DEBUG_TRANSPORT_ACTIONS
|
||||
ALOGD("channel '%s' consumer ~ sendFinishedSignal: handled=%d",
|
||||
mChannel->getName().string(), handled);
|
||||
#endif
|
||||
|
||||
return mChannel->sendSignal(handled
|
||||
? INPUT_SIGNAL_FINISHED_HANDLED
|
||||
: INPUT_SIGNAL_FINISHED_UNHANDLED);
|
||||
}
|
||||
|
||||
status_t InputConsumer::receiveDispatchSignal() {
|
||||
#if DEBUG_TRANSPORT_ACTIONS
|
||||
ALOGD("channel '%s' consumer ~ receiveDispatchSignal",
|
||||
mChannel->getName().string());
|
||||
#endif
|
||||
|
||||
char signal;
|
||||
status_t result = mChannel->receiveSignal(& signal);
|
||||
if (result) {
|
||||
return result;
|
||||
}
|
||||
if (signal != INPUT_SIGNAL_DISPATCH) {
|
||||
ALOGE("channel '%s' consumer ~ Received unexpected signal '%c' from publisher",
|
||||
mChannel->getName().string(), signal);
|
||||
return UNKNOWN_ERROR;
|
||||
}
|
||||
return OK;
|
||||
}
|
||||
|
||||
void InputConsumer::populateKeyEvent(KeyEvent* keyEvent) const {
|
||||
keyEvent->initialize(
|
||||
mSharedMessage->deviceId,
|
||||
mSharedMessage->source,
|
||||
mSharedMessage->key.action,
|
||||
mSharedMessage->key.flags,
|
||||
mSharedMessage->key.keyCode,
|
||||
mSharedMessage->key.scanCode,
|
||||
mSharedMessage->key.metaState,
|
||||
mSharedMessage->key.repeatCount,
|
||||
mSharedMessage->key.downTime,
|
||||
mSharedMessage->key.eventTime);
|
||||
}
|
||||
|
||||
void InputConsumer::populateMotionEvent(MotionEvent* motionEvent) const {
|
||||
motionEvent->initialize(
|
||||
mSharedMessage->deviceId,
|
||||
mSharedMessage->source,
|
||||
mSharedMessage->motion.action,
|
||||
mSharedMessage->motion.flags,
|
||||
mSharedMessage->motion.edgeFlags,
|
||||
mSharedMessage->motion.metaState,
|
||||
mSharedMessage->motion.buttonState,
|
||||
mSharedMessage->motion.xOffset,
|
||||
mSharedMessage->motion.yOffset,
|
||||
mSharedMessage->motion.xPrecision,
|
||||
mSharedMessage->motion.yPrecision,
|
||||
mSharedMessage->motion.downTime,
|
||||
mSharedMessage->motion.sampleData[0].eventTime,
|
||||
mSharedMessage->motion.pointerCount,
|
||||
mSharedMessage->motion.pointerProperties,
|
||||
mSharedMessage->motion.sampleData[0].coords);
|
||||
|
||||
size_t sampleCount = mSharedMessage->motion.sampleCount;
|
||||
if (sampleCount > 1) {
|
||||
InputMessage::SampleData* sampleData = mSharedMessage->motion.sampleData;
|
||||
size_t sampleDataStride = InputMessage::sampleDataStride(
|
||||
mSharedMessage->motion.pointerCount);
|
||||
|
||||
while (--sampleCount > 0) {
|
||||
sampleData = InputMessage::sampleDataPtrIncrement(sampleData, sampleDataStride);
|
||||
motionEvent->addSample(sampleData->eventTime, sampleData->coords);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace android
|
|
@ -0,0 +1,338 @@
|
|||
/*
|
||||
* Copyright (C) 2010 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef _UI_INPUT_TRANSPORT_H
|
||||
#define _UI_INPUT_TRANSPORT_H
|
||||
|
||||
/**
|
||||
* Native input transport.
|
||||
*
|
||||
* Uses anonymous shared memory as a whiteboard for sending input events from an
|
||||
* InputPublisher to an InputConsumer and ensuring appropriate synchronization.
|
||||
* One interesting feature is that published events can be updated in place as long as they
|
||||
* have not yet been consumed.
|
||||
*
|
||||
* The InputPublisher and InputConsumer only take care of transferring event data
|
||||
* over an InputChannel and sending synchronization signals. The InputDispatcher and InputQueue
|
||||
* build on these abstractions to add multiplexing and queueing.
|
||||
*/
|
||||
|
||||
#include <semaphore.h>
|
||||
#include "Input.h"
|
||||
#include <utils/Errors.h>
|
||||
#include <utils/Timers.h>
|
||||
#include <utils/RefBase.h>
|
||||
#include <utils/String8.h>
|
||||
|
||||
namespace android {
|
||||
|
||||
/*
|
||||
* An input channel consists of a shared memory buffer and a pair of pipes
|
||||
* used to send input messages from an InputPublisher to an InputConsumer
|
||||
* across processes. Each channel has a descriptive name for debugging purposes.
|
||||
*
|
||||
* Each endpoint has its own InputChannel object that specifies its own file descriptors.
|
||||
*
|
||||
* The input channel is closed when all references to it are released.
|
||||
*/
|
||||
class InputChannel : public RefBase {
|
||||
protected:
|
||||
virtual ~InputChannel();
|
||||
|
||||
public:
|
||||
InputChannel(const String8& name, int32_t ashmemFd, int32_t receivePipeFd,
|
||||
int32_t sendPipeFd);
|
||||
|
||||
/* Creates a pair of input channels and their underlying shared memory buffers
|
||||
* and pipes.
|
||||
*
|
||||
* Returns OK on success.
|
||||
*/
|
||||
static status_t openInputChannelPair(const String8& name,
|
||||
sp<InputChannel>& outServerChannel, sp<InputChannel>& outClientChannel);
|
||||
|
||||
inline String8 getName() const { return mName; }
|
||||
inline int32_t getAshmemFd() const { return mAshmemFd; }
|
||||
inline int32_t getReceivePipeFd() const { return mReceivePipeFd; }
|
||||
inline int32_t getSendPipeFd() const { return mSendPipeFd; }
|
||||
|
||||
/* Sends a signal to the other endpoint.
|
||||
*
|
||||
* Returns OK on success.
|
||||
* Returns DEAD_OBJECT if the channel's peer has been closed.
|
||||
* Other errors probably indicate that the channel is broken.
|
||||
*/
|
||||
status_t sendSignal(char signal);
|
||||
|
||||
/* Receives a signal send by the other endpoint.
|
||||
* (Should only call this after poll() indicates that the receivePipeFd has available input.)
|
||||
*
|
||||
* Returns OK on success.
|
||||
* Returns WOULD_BLOCK if there is no signal present.
|
||||
* Returns DEAD_OBJECT if the channel's peer has been closed.
|
||||
* Other errors probably indicate that the channel is broken.
|
||||
*/
|
||||
status_t receiveSignal(char* outSignal);
|
||||
|
||||
private:
|
||||
String8 mName;
|
||||
int32_t mAshmemFd;
|
||||
int32_t mReceivePipeFd;
|
||||
int32_t mSendPipeFd;
|
||||
};
|
||||
|
||||
/*
|
||||
* Private intermediate representation of input events as messages written into an
|
||||
* ashmem buffer.
|
||||
*/
|
||||
struct InputMessage {
|
||||
/* Semaphore count is set to 1 when the message is published.
|
||||
* It becomes 0 transiently while the publisher updates the message.
|
||||
* It becomes 0 permanently when the consumer consumes the message.
|
||||
*/
|
||||
sem_t semaphore;
|
||||
|
||||
/* Initialized to false by the publisher.
|
||||
* Set to true by the consumer when it consumes the message.
|
||||
*/
|
||||
bool consumed;
|
||||
|
||||
int32_t type;
|
||||
|
||||
struct SampleData {
|
||||
nsecs_t eventTime;
|
||||
PointerCoords coords[0]; // variable length
|
||||
};
|
||||
|
||||
int32_t deviceId;
|
||||
int32_t source;
|
||||
|
||||
union {
|
||||
struct {
|
||||
int32_t action;
|
||||
int32_t flags;
|
||||
int32_t keyCode;
|
||||
int32_t scanCode;
|
||||
int32_t metaState;
|
||||
int32_t repeatCount;
|
||||
nsecs_t downTime;
|
||||
nsecs_t eventTime;
|
||||
} key;
|
||||
|
||||
struct {
|
||||
int32_t action;
|
||||
int32_t flags;
|
||||
int32_t metaState;
|
||||
int32_t buttonState;
|
||||
int32_t edgeFlags;
|
||||
nsecs_t downTime;
|
||||
float xOffset;
|
||||
float yOffset;
|
||||
float xPrecision;
|
||||
float yPrecision;
|
||||
size_t pointerCount;
|
||||
PointerProperties pointerProperties[MAX_POINTERS];
|
||||
size_t sampleCount;
|
||||
SampleData sampleData[0]; // variable length
|
||||
} motion;
|
||||
};
|
||||
|
||||
/* Gets the number of bytes to add to step to the next SampleData object in a motion
|
||||
* event message for a given number of pointers.
|
||||
*/
|
||||
static inline size_t sampleDataStride(size_t pointerCount) {
|
||||
return sizeof(InputMessage::SampleData) + pointerCount * sizeof(PointerCoords);
|
||||
}
|
||||
|
||||
/* Adds the SampleData stride to the given pointer. */
|
||||
static inline SampleData* sampleDataPtrIncrement(SampleData* ptr, size_t stride) {
|
||||
return reinterpret_cast<InputMessage::SampleData*>(reinterpret_cast<char*>(ptr) + stride);
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
* Publishes input events to an anonymous shared memory buffer.
|
||||
* Uses atomic operations to coordinate shared access with a single concurrent consumer.
|
||||
*/
|
||||
class InputPublisher {
|
||||
public:
|
||||
/* Creates a publisher associated with an input channel. */
|
||||
explicit InputPublisher(const sp<InputChannel>& channel);
|
||||
|
||||
/* Destroys the publisher and releases its input channel. */
|
||||
~InputPublisher();
|
||||
|
||||
/* Gets the underlying input channel. */
|
||||
inline sp<InputChannel> getChannel() { return mChannel; }
|
||||
|
||||
/* Prepares the publisher for use. Must be called before it is used.
|
||||
* Returns OK on success.
|
||||
*
|
||||
* This method implicitly calls reset(). */
|
||||
status_t initialize();
|
||||
|
||||
/* Resets the publisher to its initial state and unpins its ashmem buffer.
|
||||
* Returns OK on success.
|
||||
*
|
||||
* Should be called after an event has been consumed to release resources used by the
|
||||
* publisher until the next event is ready to be published.
|
||||
*/
|
||||
status_t reset();
|
||||
|
||||
/* Publishes a key event to the ashmem buffer.
|
||||
*
|
||||
* Returns OK on success.
|
||||
* Returns INVALID_OPERATION if the publisher has not been reset.
|
||||
*/
|
||||
status_t publishKeyEvent(
|
||||
int32_t deviceId,
|
||||
int32_t source,
|
||||
int32_t action,
|
||||
int32_t flags,
|
||||
int32_t keyCode,
|
||||
int32_t scanCode,
|
||||
int32_t metaState,
|
||||
int32_t repeatCount,
|
||||
nsecs_t downTime,
|
||||
nsecs_t eventTime);
|
||||
|
||||
/* Publishes a motion event to the ashmem buffer.
|
||||
*
|
||||
* Returns OK on success.
|
||||
* Returns INVALID_OPERATION if the publisher has not been reset.
|
||||
* Returns BAD_VALUE if pointerCount is less than 1 or greater than MAX_POINTERS.
|
||||
*/
|
||||
status_t publishMotionEvent(
|
||||
int32_t deviceId,
|
||||
int32_t source,
|
||||
int32_t action,
|
||||
int32_t flags,
|
||||
int32_t edgeFlags,
|
||||
int32_t metaState,
|
||||
int32_t buttonState,
|
||||
float xOffset,
|
||||
float yOffset,
|
||||
float xPrecision,
|
||||
float yPrecision,
|
||||
nsecs_t downTime,
|
||||
nsecs_t eventTime,
|
||||
size_t pointerCount,
|
||||
const PointerProperties* pointerProperties,
|
||||
const PointerCoords* pointerCoords);
|
||||
|
||||
/* Appends a motion sample to a motion event unless already consumed.
|
||||
*
|
||||
* Returns OK on success.
|
||||
* Returns INVALID_OPERATION if the current event is not a AMOTION_EVENT_ACTION_MOVE event.
|
||||
* Returns FAILED_TRANSACTION if the current event has already been consumed.
|
||||
* Returns NO_MEMORY if the buffer is full and no additional samples can be added.
|
||||
*/
|
||||
status_t appendMotionSample(
|
||||
nsecs_t eventTime,
|
||||
const PointerCoords* pointerCoords);
|
||||
|
||||
/* Sends a dispatch signal to the consumer to inform it that a new message is available.
|
||||
*
|
||||
* Returns OK on success.
|
||||
* Errors probably indicate that the channel is broken.
|
||||
*/
|
||||
status_t sendDispatchSignal();
|
||||
|
||||
/* Receives the finished signal from the consumer in reply to the original dispatch signal.
|
||||
* Returns whether the consumer handled the message.
|
||||
*
|
||||
* Returns OK on success.
|
||||
* Returns WOULD_BLOCK if there is no signal present.
|
||||
* Other errors probably indicate that the channel is broken.
|
||||
*/
|
||||
status_t receiveFinishedSignal(bool* outHandled);
|
||||
|
||||
private:
|
||||
sp<InputChannel> mChannel;
|
||||
|
||||
size_t mAshmemSize;
|
||||
InputMessage* mSharedMessage;
|
||||
bool mPinned;
|
||||
bool mSemaphoreInitialized;
|
||||
bool mWasDispatched;
|
||||
|
||||
size_t mMotionEventPointerCount;
|
||||
InputMessage::SampleData* mMotionEventSampleDataTail;
|
||||
size_t mMotionEventSampleDataStride;
|
||||
|
||||
status_t publishInputEvent(
|
||||
int32_t type,
|
||||
int32_t deviceId,
|
||||
int32_t source);
|
||||
};
|
||||
|
||||
/*
|
||||
* Consumes input events from an anonymous shared memory buffer.
|
||||
* Uses atomic operations to coordinate shared access with a single concurrent publisher.
|
||||
*/
|
||||
class InputConsumer {
|
||||
public:
|
||||
/* Creates a consumer associated with an input channel. */
|
||||
explicit InputConsumer(const sp<InputChannel>& channel);
|
||||
|
||||
/* Destroys the consumer and releases its input channel. */
|
||||
~InputConsumer();
|
||||
|
||||
/* Gets the underlying input channel. */
|
||||
inline sp<InputChannel> getChannel() { return mChannel; }
|
||||
|
||||
/* Prepares the consumer for use. Must be called before it is used. */
|
||||
status_t initialize();
|
||||
|
||||
/* Consumes the input event in the buffer and copies its contents into
|
||||
* an InputEvent object created using the specified factory.
|
||||
* This operation will block if the publisher is updating the event.
|
||||
*
|
||||
* Returns OK on success.
|
||||
* Returns INVALID_OPERATION if there is no currently published event.
|
||||
* Returns NO_MEMORY if the event could not be created.
|
||||
*/
|
||||
status_t consume(InputEventFactoryInterface* factory, InputEvent** outEvent);
|
||||
|
||||
/* Sends a finished signal to the publisher to inform it that the current message is
|
||||
* finished processing and specifies whether the message was handled by the consumer.
|
||||
*
|
||||
* Returns OK on success.
|
||||
* Errors probably indicate that the channel is broken.
|
||||
*/
|
||||
status_t sendFinishedSignal(bool handled);
|
||||
|
||||
/* Receives the dispatched signal from the publisher.
|
||||
*
|
||||
* Returns OK on success.
|
||||
* Returns WOULD_BLOCK if there is no signal present.
|
||||
* Other errors probably indicate that the channel is broken.
|
||||
*/
|
||||
status_t receiveDispatchSignal();
|
||||
|
||||
private:
|
||||
sp<InputChannel> mChannel;
|
||||
|
||||
size_t mAshmemSize;
|
||||
InputMessage* mSharedMessage;
|
||||
|
||||
void populateKeyEvent(KeyEvent* keyEvent) const;
|
||||
void populateMotionEvent(MotionEvent* motionEvent) const;
|
||||
};
|
||||
|
||||
} // namespace android
|
||||
|
||||
#endif // _UI_INPUT_TRANSPORT_H
|
|
@ -0,0 +1,68 @@
|
|||
/*
|
||||
* Copyright (C) 2011 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#define LOG_TAG "InputWindow"
|
||||
|
||||
#include "InputWindow.h"
|
||||
|
||||
#include <cutils/log.h>
|
||||
|
||||
namespace android {
|
||||
|
||||
// --- InputWindowInfo ---
|
||||
|
||||
bool InputWindowInfo::touchableRegionContainsPoint(int32_t x, int32_t y) const {
|
||||
#ifdef HAVE_ANDROID_OS
|
||||
return touchableRegion.contains(x, y);
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool InputWindowInfo::frameContainsPoint(int32_t x, int32_t y) const {
|
||||
return x >= frameLeft && x <= frameRight
|
||||
&& y >= frameTop && y <= frameBottom;
|
||||
}
|
||||
|
||||
bool InputWindowInfo::isTrustedOverlay() const {
|
||||
return layoutParamsType == TYPE_INPUT_METHOD
|
||||
|| layoutParamsType == TYPE_INPUT_METHOD_DIALOG
|
||||
|| layoutParamsType == TYPE_SECURE_SYSTEM_OVERLAY;
|
||||
}
|
||||
|
||||
bool InputWindowInfo::supportsSplitTouch() const {
|
||||
return layoutParamsFlags & FLAG_SPLIT_TOUCH;
|
||||
}
|
||||
|
||||
|
||||
// --- InputWindowHandle ---
|
||||
|
||||
InputWindowHandle::InputWindowHandle(const sp<InputApplicationHandle>& inputApplicationHandle) :
|
||||
inputApplicationHandle(inputApplicationHandle), mInfo(NULL) {
|
||||
}
|
||||
|
||||
InputWindowHandle::~InputWindowHandle() {
|
||||
delete mInfo;
|
||||
}
|
||||
|
||||
void InputWindowHandle::releaseInfo() {
|
||||
if (mInfo) {
|
||||
delete mInfo;
|
||||
mInfo = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace android
|
|
@ -0,0 +1,204 @@
|
|||
/*
|
||||
* Copyright (C) 2011 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef _UI_INPUT_WINDOW_H
|
||||
#define _UI_INPUT_WINDOW_H
|
||||
|
||||
#include "Input.h"
|
||||
#include "InputTransport.h"
|
||||
#include <utils/RefBase.h>
|
||||
#include <utils/Timers.h>
|
||||
#include <utils/String8.h>
|
||||
|
||||
#include "SkRegion.h"
|
||||
|
||||
#include "InputApplication.h"
|
||||
|
||||
namespace android {
|
||||
|
||||
/*
|
||||
* Describes the properties of a window that can receive input.
|
||||
*/
|
||||
struct InputWindowInfo {
|
||||
// Window flags from WindowManager.LayoutParams
|
||||
enum {
|
||||
FLAG_ALLOW_LOCK_WHILE_SCREEN_ON = 0x00000001,
|
||||
FLAG_DIM_BEHIND = 0x00000002,
|
||||
FLAG_BLUR_BEHIND = 0x00000004,
|
||||
FLAG_NOT_FOCUSABLE = 0x00000008,
|
||||
FLAG_NOT_TOUCHABLE = 0x00000010,
|
||||
FLAG_NOT_TOUCH_MODAL = 0x00000020,
|
||||
FLAG_TOUCHABLE_WHEN_WAKING = 0x00000040,
|
||||
FLAG_KEEP_SCREEN_ON = 0x00000080,
|
||||
FLAG_LAYOUT_IN_SCREEN = 0x00000100,
|
||||
FLAG_LAYOUT_NO_LIMITS = 0x00000200,
|
||||
FLAG_FULLSCREEN = 0x00000400,
|
||||
FLAG_FORCE_NOT_FULLSCREEN = 0x00000800,
|
||||
FLAG_DITHER = 0x00001000,
|
||||
FLAG_SECURE = 0x00002000,
|
||||
FLAG_SCALED = 0x00004000,
|
||||
FLAG_IGNORE_CHEEK_PRESSES = 0x00008000,
|
||||
FLAG_LAYOUT_INSET_DECOR = 0x00010000,
|
||||
FLAG_ALT_FOCUSABLE_IM = 0x00020000,
|
||||
FLAG_WATCH_OUTSIDE_TOUCH = 0x00040000,
|
||||
FLAG_SHOW_WHEN_LOCKED = 0x00080000,
|
||||
FLAG_SHOW_WALLPAPER = 0x00100000,
|
||||
FLAG_TURN_SCREEN_ON = 0x00200000,
|
||||
FLAG_DISMISS_KEYGUARD = 0x00400000,
|
||||
FLAG_SPLIT_TOUCH = 0x00800000,
|
||||
FLAG_HARDWARE_ACCELERATED = 0x01000000,
|
||||
FLAG_HARDWARE_ACCELERATED_SYSTEM = 0x02000000,
|
||||
FLAG_SLIPPERY = 0x04000000,
|
||||
FLAG_NEEDS_MENU_KEY = 0x08000000,
|
||||
FLAG_KEEP_SURFACE_WHILE_ANIMATING = 0x10000000,
|
||||
FLAG_COMPATIBLE_WINDOW = 0x20000000,
|
||||
FLAG_SYSTEM_ERROR = 0x40000000,
|
||||
};
|
||||
|
||||
// Window types from WindowManager.LayoutParams
|
||||
enum {
|
||||
FIRST_APPLICATION_WINDOW = 1,
|
||||
TYPE_BASE_APPLICATION = 1,
|
||||
TYPE_APPLICATION = 2,
|
||||
TYPE_APPLICATION_STARTING = 3,
|
||||
LAST_APPLICATION_WINDOW = 99,
|
||||
FIRST_SUB_WINDOW = 1000,
|
||||
TYPE_APPLICATION_PANEL = FIRST_SUB_WINDOW,
|
||||
TYPE_APPLICATION_MEDIA = FIRST_SUB_WINDOW+1,
|
||||
TYPE_APPLICATION_SUB_PANEL = FIRST_SUB_WINDOW+2,
|
||||
TYPE_APPLICATION_ATTACHED_DIALOG = FIRST_SUB_WINDOW+3,
|
||||
TYPE_APPLICATION_MEDIA_OVERLAY = FIRST_SUB_WINDOW+4,
|
||||
LAST_SUB_WINDOW = 1999,
|
||||
FIRST_SYSTEM_WINDOW = 2000,
|
||||
TYPE_STATUS_BAR = FIRST_SYSTEM_WINDOW,
|
||||
TYPE_SEARCH_BAR = FIRST_SYSTEM_WINDOW+1,
|
||||
TYPE_PHONE = FIRST_SYSTEM_WINDOW+2,
|
||||
TYPE_SYSTEM_ALERT = FIRST_SYSTEM_WINDOW+3,
|
||||
TYPE_KEYGUARD = FIRST_SYSTEM_WINDOW+4,
|
||||
TYPE_TOAST = FIRST_SYSTEM_WINDOW+5,
|
||||
TYPE_SYSTEM_OVERLAY = FIRST_SYSTEM_WINDOW+6,
|
||||
TYPE_PRIORITY_PHONE = FIRST_SYSTEM_WINDOW+7,
|
||||
TYPE_SYSTEM_DIALOG = FIRST_SYSTEM_WINDOW+8,
|
||||
TYPE_KEYGUARD_DIALOG = FIRST_SYSTEM_WINDOW+9,
|
||||
TYPE_SYSTEM_ERROR = FIRST_SYSTEM_WINDOW+10,
|
||||
TYPE_INPUT_METHOD = FIRST_SYSTEM_WINDOW+11,
|
||||
TYPE_INPUT_METHOD_DIALOG= FIRST_SYSTEM_WINDOW+12,
|
||||
TYPE_WALLPAPER = FIRST_SYSTEM_WINDOW+13,
|
||||
TYPE_STATUS_BAR_PANEL = FIRST_SYSTEM_WINDOW+14,
|
||||
TYPE_SECURE_SYSTEM_OVERLAY = FIRST_SYSTEM_WINDOW+15,
|
||||
TYPE_DRAG = FIRST_SYSTEM_WINDOW+16,
|
||||
TYPE_STATUS_BAR_SUB_PANEL = FIRST_SYSTEM_WINDOW+17,
|
||||
TYPE_POINTER = FIRST_SYSTEM_WINDOW+18,
|
||||
TYPE_NAVIGATION_BAR = FIRST_SYSTEM_WINDOW+19,
|
||||
TYPE_VOLUME_OVERLAY = FIRST_SYSTEM_WINDOW+20,
|
||||
TYPE_BOOT_PROGRESS = FIRST_SYSTEM_WINDOW+21,
|
||||
LAST_SYSTEM_WINDOW = 2999,
|
||||
};
|
||||
|
||||
enum {
|
||||
INPUT_FEATURE_DISABLE_TOUCH_PAD_GESTURES = 0x00000001,
|
||||
};
|
||||
|
||||
sp<InputChannel> inputChannel;
|
||||
String8 name;
|
||||
int32_t layoutParamsFlags;
|
||||
int32_t layoutParamsType;
|
||||
nsecs_t dispatchingTimeout;
|
||||
int32_t frameLeft;
|
||||
int32_t frameTop;
|
||||
int32_t frameRight;
|
||||
int32_t frameBottom;
|
||||
float scaleFactor;
|
||||
#ifdef HAVE_ANDROID_OS
|
||||
SkRegion touchableRegion;
|
||||
#endif
|
||||
bool visible;
|
||||
bool canReceiveKeys;
|
||||
bool hasFocus;
|
||||
bool hasWallpaper;
|
||||
bool paused;
|
||||
int32_t layer;
|
||||
int32_t ownerPid;
|
||||
int32_t ownerUid;
|
||||
int32_t inputFeatures;
|
||||
|
||||
bool touchableRegionContainsPoint(int32_t x, int32_t y) const;
|
||||
bool frameContainsPoint(int32_t x, int32_t y) const;
|
||||
|
||||
/* Returns true if the window is of a trusted type that is allowed to silently
|
||||
* overlay other windows for the purpose of implementing the secure views feature.
|
||||
* Trusted overlays, such as IME windows, can partly obscure other windows without causing
|
||||
* motion events to be delivered to them with AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED.
|
||||
*/
|
||||
bool isTrustedOverlay() const;
|
||||
|
||||
bool supportsSplitTouch() const;
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* Handle for a window that can receive input.
|
||||
*
|
||||
* Used by the native input dispatcher to indirectly refer to the window manager objects
|
||||
* that describe a window.
|
||||
*/
|
||||
class InputWindowHandle : public RefBase {
|
||||
public:
|
||||
const sp<InputApplicationHandle> inputApplicationHandle;
|
||||
|
||||
inline const InputWindowInfo* getInfo() const {
|
||||
return mInfo;
|
||||
}
|
||||
|
||||
inline sp<InputChannel> getInputChannel() const {
|
||||
return mInfo ? mInfo->inputChannel : NULL;
|
||||
}
|
||||
|
||||
inline String8 getName() const {
|
||||
return mInfo ? mInfo->name : String8("<invalid>");
|
||||
}
|
||||
|
||||
inline nsecs_t getDispatchingTimeout(nsecs_t defaultValue) const {
|
||||
return mInfo ? mInfo->dispatchingTimeout : defaultValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Requests that the state of this object be updated to reflect
|
||||
* the most current available information about the application.
|
||||
*
|
||||
* This method should only be called from within the input dispatcher's
|
||||
* critical section.
|
||||
*
|
||||
* Returns true on success, or false if the handle is no longer valid.
|
||||
*/
|
||||
virtual bool updateInfo() = 0;
|
||||
|
||||
/**
|
||||
* Releases the storage used by the associated information when it is
|
||||
* no longer needed.
|
||||
*/
|
||||
void releaseInfo();
|
||||
|
||||
protected:
|
||||
InputWindowHandle(const sp<InputApplicationHandle>& inputApplicationHandle);
|
||||
virtual ~InputWindowHandle();
|
||||
|
||||
InputWindowInfo* mInfo;
|
||||
};
|
||||
|
||||
} // namespace android
|
||||
|
||||
#endif // _UI_INPUT_WINDOW_H
|
|
@ -0,0 +1,838 @@
|
|||
/*
|
||||
* Copyright (C) 2008 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#define LOG_TAG "KeyCharacterMap"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <android/keycodes.h>
|
||||
#include "Keyboard.h"
|
||||
#include "KeyCharacterMap.h"
|
||||
#include <utils/Log.h>
|
||||
#include <utils/Errors.h>
|
||||
#include <utils/Tokenizer.h>
|
||||
#include <utils/Timers.h>
|
||||
|
||||
// Enables debug output for the parser.
|
||||
#define DEBUG_PARSER 0
|
||||
|
||||
// Enables debug output for parser performance.
|
||||
#define DEBUG_PARSER_PERFORMANCE 0
|
||||
|
||||
// Enables debug output for mapping.
|
||||
#define DEBUG_MAPPING 0
|
||||
|
||||
|
||||
namespace android {
|
||||
|
||||
static const char* WHITESPACE = " \t\r";
|
||||
static const char* WHITESPACE_OR_PROPERTY_DELIMITER = " \t\r,:";
|
||||
|
||||
struct Modifier {
|
||||
const char* label;
|
||||
int32_t metaState;
|
||||
};
|
||||
static const Modifier modifiers[] = {
|
||||
{ "shift", AMETA_SHIFT_ON },
|
||||
{ "lshift", AMETA_SHIFT_LEFT_ON },
|
||||
{ "rshift", AMETA_SHIFT_RIGHT_ON },
|
||||
{ "alt", AMETA_ALT_ON },
|
||||
{ "lalt", AMETA_ALT_LEFT_ON },
|
||||
{ "ralt", AMETA_ALT_RIGHT_ON },
|
||||
{ "ctrl", AMETA_CTRL_ON },
|
||||
{ "lctrl", AMETA_CTRL_LEFT_ON },
|
||||
{ "rctrl", AMETA_CTRL_RIGHT_ON },
|
||||
{ "meta", AMETA_META_ON },
|
||||
{ "lmeta", AMETA_META_LEFT_ON },
|
||||
{ "rmeta", AMETA_META_RIGHT_ON },
|
||||
{ "sym", AMETA_SYM_ON },
|
||||
{ "fn", AMETA_FUNCTION_ON },
|
||||
{ "capslock", AMETA_CAPS_LOCK_ON },
|
||||
{ "numlock", AMETA_NUM_LOCK_ON },
|
||||
{ "scrolllock", AMETA_SCROLL_LOCK_ON },
|
||||
};
|
||||
|
||||
#if DEBUG_MAPPING
|
||||
static String8 toString(const char16_t* chars, size_t numChars) {
|
||||
String8 result;
|
||||
for (size_t i = 0; i < numChars; i++) {
|
||||
result.appendFormat(i == 0 ? "%d" : ", %d", chars[i]);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
// --- KeyCharacterMap ---
|
||||
|
||||
KeyCharacterMap::KeyCharacterMap() :
|
||||
mType(KEYBOARD_TYPE_UNKNOWN) {
|
||||
}
|
||||
|
||||
KeyCharacterMap::~KeyCharacterMap() {
|
||||
for (size_t i = 0; i < mKeys.size(); i++) {
|
||||
Key* key = mKeys.editValueAt(i);
|
||||
delete key;
|
||||
}
|
||||
}
|
||||
|
||||
status_t KeyCharacterMap::load(const String8& filename, KeyCharacterMap** outMap) {
|
||||
*outMap = NULL;
|
||||
|
||||
Tokenizer* tokenizer;
|
||||
status_t status = Tokenizer::open(filename, &tokenizer);
|
||||
if (status) {
|
||||
ALOGE("Error %d opening key character map file %s.", status, filename.string());
|
||||
} else {
|
||||
KeyCharacterMap* map = new KeyCharacterMap();
|
||||
if (!map) {
|
||||
ALOGE("Error allocating key character map.");
|
||||
status = NO_MEMORY;
|
||||
} else {
|
||||
#if DEBUG_PARSER_PERFORMANCE
|
||||
nsecs_t startTime = systemTime(SYSTEM_TIME_MONOTONIC);
|
||||
#endif
|
||||
Parser parser(map, tokenizer);
|
||||
status = parser.parse();
|
||||
#if DEBUG_PARSER_PERFORMANCE
|
||||
nsecs_t elapsedTime = systemTime(SYSTEM_TIME_MONOTONIC) - startTime;
|
||||
ALOGD("Parsed key character map file '%s' %d lines in %0.3fms.",
|
||||
tokenizer->getFilename().string(), tokenizer->getLineNumber(),
|
||||
elapsedTime / 1000000.0);
|
||||
#endif
|
||||
if (status) {
|
||||
delete map;
|
||||
} else {
|
||||
*outMap = map;
|
||||
}
|
||||
}
|
||||
delete tokenizer;
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
int32_t KeyCharacterMap::getKeyboardType() const {
|
||||
return mType;
|
||||
}
|
||||
|
||||
char16_t KeyCharacterMap::getDisplayLabel(int32_t keyCode) const {
|
||||
char16_t result = 0;
|
||||
const Key* key;
|
||||
if (getKey(keyCode, &key)) {
|
||||
result = key->label;
|
||||
}
|
||||
#if DEBUG_MAPPING
|
||||
ALOGD("getDisplayLabel: keyCode=%d ~ Result %d.", keyCode, result);
|
||||
#endif
|
||||
return result;
|
||||
}
|
||||
|
||||
char16_t KeyCharacterMap::getNumber(int32_t keyCode) const {
|
||||
char16_t result = 0;
|
||||
const Key* key;
|
||||
if (getKey(keyCode, &key)) {
|
||||
result = key->number;
|
||||
}
|
||||
#if DEBUG_MAPPING
|
||||
ALOGD("getNumber: keyCode=%d ~ Result %d.", keyCode, result);
|
||||
#endif
|
||||
return result;
|
||||
}
|
||||
|
||||
char16_t KeyCharacterMap::getCharacter(int32_t keyCode, int32_t metaState) const {
|
||||
char16_t result = 0;
|
||||
const Key* key;
|
||||
const Behavior* behavior;
|
||||
if (getKeyBehavior(keyCode, metaState, &key, &behavior)) {
|
||||
result = behavior->character;
|
||||
}
|
||||
#if DEBUG_MAPPING
|
||||
ALOGD("getCharacter: keyCode=%d, metaState=0x%08x ~ Result %d.", keyCode, metaState, result);
|
||||
#endif
|
||||
return result;
|
||||
}
|
||||
|
||||
bool KeyCharacterMap::getFallbackAction(int32_t keyCode, int32_t metaState,
|
||||
FallbackAction* outFallbackAction) const {
|
||||
outFallbackAction->keyCode = 0;
|
||||
outFallbackAction->metaState = 0;
|
||||
|
||||
bool result = false;
|
||||
const Key* key;
|
||||
const Behavior* behavior;
|
||||
if (getKeyBehavior(keyCode, metaState, &key, &behavior)) {
|
||||
if (behavior->fallbackKeyCode) {
|
||||
outFallbackAction->keyCode = behavior->fallbackKeyCode;
|
||||
outFallbackAction->metaState = metaState & ~behavior->metaState;
|
||||
result = true;
|
||||
}
|
||||
}
|
||||
#if DEBUG_MAPPING
|
||||
ALOGD("getFallbackKeyCode: keyCode=%d, metaState=0x%08x ~ Result %s, "
|
||||
"fallback keyCode=%d, fallback metaState=0x%08x.",
|
||||
keyCode, metaState, result ? "true" : "false",
|
||||
outFallbackAction->keyCode, outFallbackAction->metaState);
|
||||
#endif
|
||||
return result;
|
||||
}
|
||||
|
||||
char16_t KeyCharacterMap::getMatch(int32_t keyCode, const char16_t* chars, size_t numChars,
|
||||
int32_t metaState) const {
|
||||
char16_t result = 0;
|
||||
const Key* key;
|
||||
if (getKey(keyCode, &key)) {
|
||||
// Try to find the most general behavior that maps to this character.
|
||||
// For example, the base key behavior will usually be last in the list.
|
||||
// However, if we find a perfect meta state match for one behavior then use that one.
|
||||
for (const Behavior* behavior = key->firstBehavior; behavior; behavior = behavior->next) {
|
||||
if (behavior->character) {
|
||||
for (size_t i = 0; i < numChars; i++) {
|
||||
if (behavior->character == chars[i]) {
|
||||
result = behavior->character;
|
||||
if ((behavior->metaState & metaState) == behavior->metaState) {
|
||||
goto ExactMatch;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
ExactMatch: ;
|
||||
}
|
||||
#if DEBUG_MAPPING
|
||||
ALOGD("getMatch: keyCode=%d, chars=[%s], metaState=0x%08x ~ Result %d.",
|
||||
keyCode, toString(chars, numChars).string(), metaState, result);
|
||||
#endif
|
||||
return result;
|
||||
}
|
||||
|
||||
bool KeyCharacterMap::getEvents(int32_t deviceId, const char16_t* chars, size_t numChars,
|
||||
Vector<KeyEvent>& outEvents) const {
|
||||
nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
|
||||
|
||||
for (size_t i = 0; i < numChars; i++) {
|
||||
int32_t keyCode, metaState;
|
||||
char16_t ch = chars[i];
|
||||
if (!findKey(ch, &keyCode, &metaState)) {
|
||||
#if DEBUG_MAPPING
|
||||
ALOGD("getEvents: deviceId=%d, chars=[%s] ~ Failed to find mapping for character %d.",
|
||||
deviceId, toString(chars, numChars).string(), ch);
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
int32_t currentMetaState = 0;
|
||||
addMetaKeys(outEvents, deviceId, metaState, true, now, ¤tMetaState);
|
||||
addKey(outEvents, deviceId, keyCode, currentMetaState, true, now);
|
||||
addKey(outEvents, deviceId, keyCode, currentMetaState, false, now);
|
||||
addMetaKeys(outEvents, deviceId, metaState, false, now, ¤tMetaState);
|
||||
}
|
||||
#if DEBUG_MAPPING
|
||||
ALOGD("getEvents: deviceId=%d, chars=[%s] ~ Generated %d events.",
|
||||
deviceId, toString(chars, numChars).string(), int32_t(outEvents.size()));
|
||||
for (size_t i = 0; i < outEvents.size(); i++) {
|
||||
ALOGD(" Key: keyCode=%d, metaState=0x%08x, %s.",
|
||||
outEvents[i].getKeyCode(), outEvents[i].getMetaState(),
|
||||
outEvents[i].getAction() == AKEY_EVENT_ACTION_DOWN ? "down" : "up");
|
||||
}
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
bool KeyCharacterMap::getKey(int32_t keyCode, const Key** outKey) const {
|
||||
ssize_t index = mKeys.indexOfKey(keyCode);
|
||||
if (index >= 0) {
|
||||
*outKey = mKeys.valueAt(index);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool KeyCharacterMap::getKeyBehavior(int32_t keyCode, int32_t metaState,
|
||||
const Key** outKey, const Behavior** outBehavior) const {
|
||||
const Key* key;
|
||||
if (getKey(keyCode, &key)) {
|
||||
const Behavior* behavior = key->firstBehavior;
|
||||
while (behavior) {
|
||||
if ((behavior->metaState & metaState) == behavior->metaState) {
|
||||
*outKey = key;
|
||||
*outBehavior = behavior;
|
||||
return true;
|
||||
}
|
||||
behavior = behavior->next;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool KeyCharacterMap::findKey(char16_t ch, int32_t* outKeyCode, int32_t* outMetaState) const {
|
||||
if (!ch) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < mKeys.size(); i++) {
|
||||
const Key* key = mKeys.valueAt(i);
|
||||
|
||||
// Try to find the most general behavior that maps to this character.
|
||||
// For example, the base key behavior will usually be last in the list.
|
||||
const Behavior* found = NULL;
|
||||
for (const Behavior* behavior = key->firstBehavior; behavior; behavior = behavior->next) {
|
||||
if (behavior->character == ch) {
|
||||
found = behavior;
|
||||
}
|
||||
}
|
||||
if (found) {
|
||||
*outKeyCode = mKeys.keyAt(i);
|
||||
*outMetaState = found->metaState;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void KeyCharacterMap::addKey(Vector<KeyEvent>& outEvents,
|
||||
int32_t deviceId, int32_t keyCode, int32_t metaState, bool down, nsecs_t time) {
|
||||
outEvents.push();
|
||||
KeyEvent& event = outEvents.editTop();
|
||||
event.initialize(deviceId, AINPUT_SOURCE_KEYBOARD,
|
||||
down ? AKEY_EVENT_ACTION_DOWN : AKEY_EVENT_ACTION_UP,
|
||||
0, keyCode, 0, metaState, 0, time, time);
|
||||
}
|
||||
|
||||
void KeyCharacterMap::addMetaKeys(Vector<KeyEvent>& outEvents,
|
||||
int32_t deviceId, int32_t metaState, bool down, nsecs_t time,
|
||||
int32_t* currentMetaState) {
|
||||
// Add and remove meta keys symmetrically.
|
||||
if (down) {
|
||||
addLockedMetaKey(outEvents, deviceId, metaState, time,
|
||||
AKEYCODE_CAPS_LOCK, AMETA_CAPS_LOCK_ON, currentMetaState);
|
||||
addLockedMetaKey(outEvents, deviceId, metaState, time,
|
||||
AKEYCODE_NUM_LOCK, AMETA_NUM_LOCK_ON, currentMetaState);
|
||||
addLockedMetaKey(outEvents, deviceId, metaState, time,
|
||||
AKEYCODE_SCROLL_LOCK, AMETA_SCROLL_LOCK_ON, currentMetaState);
|
||||
|
||||
addDoubleEphemeralMetaKey(outEvents, deviceId, metaState, true, time,
|
||||
AKEYCODE_SHIFT_LEFT, AMETA_SHIFT_LEFT_ON,
|
||||
AKEYCODE_SHIFT_RIGHT, AMETA_SHIFT_RIGHT_ON,
|
||||
AMETA_SHIFT_ON, currentMetaState);
|
||||
addDoubleEphemeralMetaKey(outEvents, deviceId, metaState, true, time,
|
||||
AKEYCODE_ALT_LEFT, AMETA_ALT_LEFT_ON,
|
||||
AKEYCODE_ALT_RIGHT, AMETA_ALT_RIGHT_ON,
|
||||
AMETA_ALT_ON, currentMetaState);
|
||||
addDoubleEphemeralMetaKey(outEvents, deviceId, metaState, true, time,
|
||||
AKEYCODE_CTRL_LEFT, AMETA_CTRL_LEFT_ON,
|
||||
AKEYCODE_CTRL_RIGHT, AMETA_CTRL_RIGHT_ON,
|
||||
AMETA_CTRL_ON, currentMetaState);
|
||||
addDoubleEphemeralMetaKey(outEvents, deviceId, metaState, true, time,
|
||||
AKEYCODE_META_LEFT, AMETA_META_LEFT_ON,
|
||||
AKEYCODE_META_RIGHT, AMETA_META_RIGHT_ON,
|
||||
AMETA_META_ON, currentMetaState);
|
||||
|
||||
addSingleEphemeralMetaKey(outEvents, deviceId, metaState, true, time,
|
||||
AKEYCODE_SYM, AMETA_SYM_ON, currentMetaState);
|
||||
addSingleEphemeralMetaKey(outEvents, deviceId, metaState, true, time,
|
||||
AKEYCODE_FUNCTION, AMETA_FUNCTION_ON, currentMetaState);
|
||||
} else {
|
||||
addSingleEphemeralMetaKey(outEvents, deviceId, metaState, false, time,
|
||||
AKEYCODE_FUNCTION, AMETA_FUNCTION_ON, currentMetaState);
|
||||
addSingleEphemeralMetaKey(outEvents, deviceId, metaState, false, time,
|
||||
AKEYCODE_SYM, AMETA_SYM_ON, currentMetaState);
|
||||
|
||||
addDoubleEphemeralMetaKey(outEvents, deviceId, metaState, false, time,
|
||||
AKEYCODE_META_LEFT, AMETA_META_LEFT_ON,
|
||||
AKEYCODE_META_RIGHT, AMETA_META_RIGHT_ON,
|
||||
AMETA_META_ON, currentMetaState);
|
||||
addDoubleEphemeralMetaKey(outEvents, deviceId, metaState, false, time,
|
||||
AKEYCODE_CTRL_LEFT, AMETA_CTRL_LEFT_ON,
|
||||
AKEYCODE_CTRL_RIGHT, AMETA_CTRL_RIGHT_ON,
|
||||
AMETA_CTRL_ON, currentMetaState);
|
||||
addDoubleEphemeralMetaKey(outEvents, deviceId, metaState, false, time,
|
||||
AKEYCODE_ALT_LEFT, AMETA_ALT_LEFT_ON,
|
||||
AKEYCODE_ALT_RIGHT, AMETA_ALT_RIGHT_ON,
|
||||
AMETA_ALT_ON, currentMetaState);
|
||||
addDoubleEphemeralMetaKey(outEvents, deviceId, metaState, false, time,
|
||||
AKEYCODE_SHIFT_LEFT, AMETA_SHIFT_LEFT_ON,
|
||||
AKEYCODE_SHIFT_RIGHT, AMETA_SHIFT_RIGHT_ON,
|
||||
AMETA_SHIFT_ON, currentMetaState);
|
||||
|
||||
addLockedMetaKey(outEvents, deviceId, metaState, time,
|
||||
AKEYCODE_SCROLL_LOCK, AMETA_SCROLL_LOCK_ON, currentMetaState);
|
||||
addLockedMetaKey(outEvents, deviceId, metaState, time,
|
||||
AKEYCODE_NUM_LOCK, AMETA_NUM_LOCK_ON, currentMetaState);
|
||||
addLockedMetaKey(outEvents, deviceId, metaState, time,
|
||||
AKEYCODE_CAPS_LOCK, AMETA_CAPS_LOCK_ON, currentMetaState);
|
||||
}
|
||||
}
|
||||
|
||||
bool KeyCharacterMap::addSingleEphemeralMetaKey(Vector<KeyEvent>& outEvents,
|
||||
int32_t deviceId, int32_t metaState, bool down, nsecs_t time,
|
||||
int32_t keyCode, int32_t keyMetaState,
|
||||
int32_t* currentMetaState) {
|
||||
if ((metaState & keyMetaState) == keyMetaState) {
|
||||
*currentMetaState = updateMetaState(keyCode, down, *currentMetaState);
|
||||
addKey(outEvents, deviceId, keyCode, *currentMetaState, down, time);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void KeyCharacterMap::addDoubleEphemeralMetaKey(Vector<KeyEvent>& outEvents,
|
||||
int32_t deviceId, int32_t metaState, bool down, nsecs_t time,
|
||||
int32_t leftKeyCode, int32_t leftKeyMetaState,
|
||||
int32_t rightKeyCode, int32_t rightKeyMetaState,
|
||||
int32_t eitherKeyMetaState,
|
||||
int32_t* currentMetaState) {
|
||||
bool specific = false;
|
||||
specific |= addSingleEphemeralMetaKey(outEvents, deviceId, metaState, down, time,
|
||||
leftKeyCode, leftKeyMetaState, currentMetaState);
|
||||
specific |= addSingleEphemeralMetaKey(outEvents, deviceId, metaState, down, time,
|
||||
rightKeyCode, rightKeyMetaState, currentMetaState);
|
||||
|
||||
if (!specific) {
|
||||
addSingleEphemeralMetaKey(outEvents, deviceId, metaState, down, time,
|
||||
leftKeyCode, eitherKeyMetaState, currentMetaState);
|
||||
}
|
||||
}
|
||||
|
||||
void KeyCharacterMap::addLockedMetaKey(Vector<KeyEvent>& outEvents,
|
||||
int32_t deviceId, int32_t metaState, nsecs_t time,
|
||||
int32_t keyCode, int32_t keyMetaState,
|
||||
int32_t* currentMetaState) {
|
||||
if ((metaState & keyMetaState) == keyMetaState) {
|
||||
*currentMetaState = updateMetaState(keyCode, true, *currentMetaState);
|
||||
addKey(outEvents, deviceId, keyCode, *currentMetaState, true, time);
|
||||
*currentMetaState = updateMetaState(keyCode, false, *currentMetaState);
|
||||
addKey(outEvents, deviceId, keyCode, *currentMetaState, false, time);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// --- KeyCharacterMap::Key ---
|
||||
|
||||
KeyCharacterMap::Key::Key() :
|
||||
label(0), number(0), firstBehavior(NULL) {
|
||||
}
|
||||
|
||||
KeyCharacterMap::Key::~Key() {
|
||||
Behavior* behavior = firstBehavior;
|
||||
while (behavior) {
|
||||
Behavior* next = behavior->next;
|
||||
delete behavior;
|
||||
behavior = next;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// --- KeyCharacterMap::Behavior ---
|
||||
|
||||
KeyCharacterMap::Behavior::Behavior() :
|
||||
next(NULL), metaState(0), character(0), fallbackKeyCode(0) {
|
||||
}
|
||||
|
||||
|
||||
// --- KeyCharacterMap::Parser ---
|
||||
|
||||
KeyCharacterMap::Parser::Parser(KeyCharacterMap* map, Tokenizer* tokenizer) :
|
||||
mMap(map), mTokenizer(tokenizer), mState(STATE_TOP) {
|
||||
}
|
||||
|
||||
KeyCharacterMap::Parser::~Parser() {
|
||||
}
|
||||
|
||||
status_t KeyCharacterMap::Parser::parse() {
|
||||
while (!mTokenizer->isEof()) {
|
||||
#if DEBUG_PARSER
|
||||
ALOGD("Parsing %s: '%s'.", mTokenizer->getLocation().string(),
|
||||
mTokenizer->peekRemainderOfLine().string());
|
||||
#endif
|
||||
|
||||
mTokenizer->skipDelimiters(WHITESPACE);
|
||||
|
||||
if (!mTokenizer->isEol() && mTokenizer->peekChar() != '#') {
|
||||
switch (mState) {
|
||||
case STATE_TOP: {
|
||||
String8 keywordToken = mTokenizer->nextToken(WHITESPACE);
|
||||
if (keywordToken == "type") {
|
||||
mTokenizer->skipDelimiters(WHITESPACE);
|
||||
status_t status = parseType();
|
||||
if (status) return status;
|
||||
} else if (keywordToken == "key") {
|
||||
mTokenizer->skipDelimiters(WHITESPACE);
|
||||
status_t status = parseKey();
|
||||
if (status) return status;
|
||||
} else {
|
||||
ALOGE("%s: Expected keyword, got '%s'.", mTokenizer->getLocation().string(),
|
||||
keywordToken.string());
|
||||
return BAD_VALUE;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case STATE_KEY: {
|
||||
status_t status = parseKeyProperty();
|
||||
if (status) return status;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
mTokenizer->skipDelimiters(WHITESPACE);
|
||||
if (!mTokenizer->isEol()) {
|
||||
ALOGE("%s: Expected end of line, got '%s'.",
|
||||
mTokenizer->getLocation().string(),
|
||||
mTokenizer->peekRemainderOfLine().string());
|
||||
return BAD_VALUE;
|
||||
}
|
||||
}
|
||||
|
||||
mTokenizer->nextLine();
|
||||
}
|
||||
|
||||
if (mState != STATE_TOP) {
|
||||
ALOGE("%s: Unterminated key description at end of file.",
|
||||
mTokenizer->getLocation().string());
|
||||
return BAD_VALUE;
|
||||
}
|
||||
|
||||
if (mMap->mType == KEYBOARD_TYPE_UNKNOWN) {
|
||||
ALOGE("%s: Missing required keyboard 'type' declaration.",
|
||||
mTokenizer->getLocation().string());
|
||||
return BAD_VALUE;
|
||||
}
|
||||
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
status_t KeyCharacterMap::Parser::parseType() {
|
||||
if (mMap->mType != KEYBOARD_TYPE_UNKNOWN) {
|
||||
ALOGE("%s: Duplicate keyboard 'type' declaration.",
|
||||
mTokenizer->getLocation().string());
|
||||
return BAD_VALUE;
|
||||
}
|
||||
|
||||
KeyboardType type;
|
||||
String8 typeToken = mTokenizer->nextToken(WHITESPACE);
|
||||
if (typeToken == "NUMERIC") {
|
||||
type = KEYBOARD_TYPE_NUMERIC;
|
||||
} else if (typeToken == "PREDICTIVE") {
|
||||
type = KEYBOARD_TYPE_PREDICTIVE;
|
||||
} else if (typeToken == "ALPHA") {
|
||||
type = KEYBOARD_TYPE_ALPHA;
|
||||
} else if (typeToken == "FULL") {
|
||||
type = KEYBOARD_TYPE_FULL;
|
||||
} else if (typeToken == "SPECIAL_FUNCTION") {
|
||||
type = KEYBOARD_TYPE_SPECIAL_FUNCTION;
|
||||
} else {
|
||||
ALOGE("%s: Expected keyboard type label, got '%s'.", mTokenizer->getLocation().string(),
|
||||
typeToken.string());
|
||||
return BAD_VALUE;
|
||||
}
|
||||
|
||||
#if DEBUG_PARSER
|
||||
ALOGD("Parsed type: type=%d.", type);
|
||||
#endif
|
||||
mMap->mType = type;
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
status_t KeyCharacterMap::Parser::parseKey() {
|
||||
String8 keyCodeToken = mTokenizer->nextToken(WHITESPACE);
|
||||
int32_t keyCode = getKeyCodeByLabel(keyCodeToken.string());
|
||||
if (!keyCode) {
|
||||
ALOGE("%s: Expected key code label, got '%s'.", mTokenizer->getLocation().string(),
|
||||
keyCodeToken.string());
|
||||
return BAD_VALUE;
|
||||
}
|
||||
if (mMap->mKeys.indexOfKey(keyCode) >= 0) {
|
||||
ALOGE("%s: Duplicate entry for key code '%s'.", mTokenizer->getLocation().string(),
|
||||
keyCodeToken.string());
|
||||
return BAD_VALUE;
|
||||
}
|
||||
|
||||
mTokenizer->skipDelimiters(WHITESPACE);
|
||||
String8 openBraceToken = mTokenizer->nextToken(WHITESPACE);
|
||||
if (openBraceToken != "{") {
|
||||
ALOGE("%s: Expected '{' after key code label, got '%s'.",
|
||||
mTokenizer->getLocation().string(), openBraceToken.string());
|
||||
return BAD_VALUE;
|
||||
}
|
||||
|
||||
#if DEBUG_PARSER
|
||||
ALOGD("Parsed beginning of key: keyCode=%d.", keyCode);
|
||||
#endif
|
||||
mKeyCode = keyCode;
|
||||
mMap->mKeys.add(keyCode, new Key());
|
||||
mState = STATE_KEY;
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
status_t KeyCharacterMap::Parser::parseKeyProperty() {
|
||||
String8 token = mTokenizer->nextToken(WHITESPACE_OR_PROPERTY_DELIMITER);
|
||||
if (token == "}") {
|
||||
mState = STATE_TOP;
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
Vector<Property> properties;
|
||||
|
||||
// Parse all comma-delimited property names up to the first colon.
|
||||
for (;;) {
|
||||
if (token == "label") {
|
||||
properties.add(Property(PROPERTY_LABEL));
|
||||
} else if (token == "number") {
|
||||
properties.add(Property(PROPERTY_NUMBER));
|
||||
} else {
|
||||
int32_t metaState;
|
||||
status_t status = parseModifier(token, &metaState);
|
||||
if (status) {
|
||||
ALOGE("%s: Expected a property name or modifier, got '%s'.",
|
||||
mTokenizer->getLocation().string(), token.string());
|
||||
return status;
|
||||
}
|
||||
properties.add(Property(PROPERTY_META, metaState));
|
||||
}
|
||||
|
||||
mTokenizer->skipDelimiters(WHITESPACE);
|
||||
if (!mTokenizer->isEol()) {
|
||||
char ch = mTokenizer->nextChar();
|
||||
if (ch == ':') {
|
||||
break;
|
||||
} else if (ch == ',') {
|
||||
mTokenizer->skipDelimiters(WHITESPACE);
|
||||
token = mTokenizer->nextToken(WHITESPACE_OR_PROPERTY_DELIMITER);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
ALOGE("%s: Expected ',' or ':' after property name.",
|
||||
mTokenizer->getLocation().string());
|
||||
return BAD_VALUE;
|
||||
}
|
||||
|
||||
// Parse behavior after the colon.
|
||||
mTokenizer->skipDelimiters(WHITESPACE);
|
||||
|
||||
Behavior behavior;
|
||||
bool haveCharacter = false;
|
||||
bool haveFallback = false;
|
||||
|
||||
do {
|
||||
char ch = mTokenizer->peekChar();
|
||||
if (ch == '\'') {
|
||||
char16_t character;
|
||||
status_t status = parseCharacterLiteral(&character);
|
||||
if (status || !character) {
|
||||
ALOGE("%s: Invalid character literal for key.",
|
||||
mTokenizer->getLocation().string());
|
||||
return BAD_VALUE;
|
||||
}
|
||||
if (haveCharacter) {
|
||||
ALOGE("%s: Cannot combine multiple character literals or 'none'.",
|
||||
mTokenizer->getLocation().string());
|
||||
return BAD_VALUE;
|
||||
}
|
||||
behavior.character = character;
|
||||
haveCharacter = true;
|
||||
} else {
|
||||
token = mTokenizer->nextToken(WHITESPACE);
|
||||
if (token == "none") {
|
||||
if (haveCharacter) {
|
||||
ALOGE("%s: Cannot combine multiple character literals or 'none'.",
|
||||
mTokenizer->getLocation().string());
|
||||
return BAD_VALUE;
|
||||
}
|
||||
haveCharacter = true;
|
||||
} else if (token == "fallback") {
|
||||
mTokenizer->skipDelimiters(WHITESPACE);
|
||||
token = mTokenizer->nextToken(WHITESPACE);
|
||||
int32_t keyCode = getKeyCodeByLabel(token.string());
|
||||
if (!keyCode) {
|
||||
ALOGE("%s: Invalid key code label for fallback behavior, got '%s'.",
|
||||
mTokenizer->getLocation().string(),
|
||||
token.string());
|
||||
return BAD_VALUE;
|
||||
}
|
||||
if (haveFallback) {
|
||||
ALOGE("%s: Cannot combine multiple fallback key codes.",
|
||||
mTokenizer->getLocation().string());
|
||||
return BAD_VALUE;
|
||||
}
|
||||
behavior.fallbackKeyCode = keyCode;
|
||||
haveFallback = true;
|
||||
} else {
|
||||
ALOGE("%s: Expected a key behavior after ':'.",
|
||||
mTokenizer->getLocation().string());
|
||||
return BAD_VALUE;
|
||||
}
|
||||
}
|
||||
|
||||
mTokenizer->skipDelimiters(WHITESPACE);
|
||||
} while (!mTokenizer->isEol());
|
||||
|
||||
// Add the behavior.
|
||||
Key* key = mMap->mKeys.valueFor(mKeyCode);
|
||||
for (size_t i = 0; i < properties.size(); i++) {
|
||||
const Property& property = properties.itemAt(i);
|
||||
switch (property.property) {
|
||||
case PROPERTY_LABEL:
|
||||
if (key->label) {
|
||||
ALOGE("%s: Duplicate label for key.",
|
||||
mTokenizer->getLocation().string());
|
||||
return BAD_VALUE;
|
||||
}
|
||||
key->label = behavior.character;
|
||||
#if DEBUG_PARSER
|
||||
ALOGD("Parsed key label: keyCode=%d, label=%d.", mKeyCode, key->label);
|
||||
#endif
|
||||
break;
|
||||
case PROPERTY_NUMBER:
|
||||
if (key->number) {
|
||||
ALOGE("%s: Duplicate number for key.",
|
||||
mTokenizer->getLocation().string());
|
||||
return BAD_VALUE;
|
||||
}
|
||||
key->number = behavior.character;
|
||||
#if DEBUG_PARSER
|
||||
ALOGD("Parsed key number: keyCode=%d, number=%d.", mKeyCode, key->number);
|
||||
#endif
|
||||
break;
|
||||
case PROPERTY_META: {
|
||||
for (Behavior* b = key->firstBehavior; b; b = b->next) {
|
||||
if (b->metaState == property.metaState) {
|
||||
ALOGE("%s: Duplicate key behavior for modifier.",
|
||||
mTokenizer->getLocation().string());
|
||||
return BAD_VALUE;
|
||||
}
|
||||
}
|
||||
Behavior* newBehavior = new Behavior(behavior);
|
||||
newBehavior->metaState = property.metaState;
|
||||
newBehavior->next = key->firstBehavior;
|
||||
key->firstBehavior = newBehavior;
|
||||
#if DEBUG_PARSER
|
||||
ALOGD("Parsed key meta: keyCode=%d, meta=0x%x, char=%d, fallback=%d.", mKeyCode,
|
||||
newBehavior->metaState, newBehavior->character, newBehavior->fallbackKeyCode);
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
status_t KeyCharacterMap::Parser::parseModifier(const String8& token, int32_t* outMetaState) {
|
||||
if (token == "base") {
|
||||
*outMetaState = 0;
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
int32_t combinedMeta = 0;
|
||||
|
||||
const char* str = token.string();
|
||||
const char* start = str;
|
||||
for (const char* cur = str; ; cur++) {
|
||||
char ch = *cur;
|
||||
if (ch == '+' || ch == '\0') {
|
||||
size_t len = cur - start;
|
||||
int32_t metaState = 0;
|
||||
for (size_t i = 0; i < sizeof(modifiers) / sizeof(Modifier); i++) {
|
||||
if (strlen(modifiers[i].label) == len
|
||||
&& strncmp(modifiers[i].label, start, len) == 0) {
|
||||
metaState = modifiers[i].metaState;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!metaState) {
|
||||
return BAD_VALUE;
|
||||
}
|
||||
if (combinedMeta & metaState) {
|
||||
ALOGE("%s: Duplicate modifier combination '%s'.",
|
||||
mTokenizer->getLocation().string(), token.string());
|
||||
return BAD_VALUE;
|
||||
}
|
||||
|
||||
combinedMeta |= metaState;
|
||||
start = cur + 1;
|
||||
|
||||
if (ch == '\0') {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
*outMetaState = combinedMeta;
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
status_t KeyCharacterMap::Parser::parseCharacterLiteral(char16_t* outCharacter) {
|
||||
char ch = mTokenizer->nextChar();
|
||||
if (ch != '\'') {
|
||||
goto Error;
|
||||
}
|
||||
|
||||
ch = mTokenizer->nextChar();
|
||||
if (ch == '\\') {
|
||||
// Escape sequence.
|
||||
ch = mTokenizer->nextChar();
|
||||
if (ch == 'n') {
|
||||
*outCharacter = '\n';
|
||||
} else if (ch == 't') {
|
||||
*outCharacter = '\t';
|
||||
} else if (ch == '\\') {
|
||||
*outCharacter = '\\';
|
||||
} else if (ch == '\'') {
|
||||
*outCharacter = '\'';
|
||||
} else if (ch == '"') {
|
||||
*outCharacter = '"';
|
||||
} else if (ch == 'u') {
|
||||
*outCharacter = 0;
|
||||
for (int i = 0; i < 4; i++) {
|
||||
ch = mTokenizer->nextChar();
|
||||
int digit;
|
||||
if (ch >= '0' && ch <= '9') {
|
||||
digit = ch - '0';
|
||||
} else if (ch >= 'A' && ch <= 'F') {
|
||||
digit = ch - 'A' + 10;
|
||||
} else if (ch >= 'a' && ch <= 'f') {
|
||||
digit = ch - 'a' + 10;
|
||||
} else {
|
||||
goto Error;
|
||||
}
|
||||
*outCharacter = (*outCharacter << 4) | digit;
|
||||
}
|
||||
} else {
|
||||
goto Error;
|
||||
}
|
||||
} else if (ch >= 32 && ch <= 126 && ch != '\'') {
|
||||
// ASCII literal character.
|
||||
*outCharacter = ch;
|
||||
} else {
|
||||
goto Error;
|
||||
}
|
||||
|
||||
ch = mTokenizer->nextChar();
|
||||
if (ch != '\'') {
|
||||
goto Error;
|
||||
}
|
||||
|
||||
// Ensure that we consumed the entire token.
|
||||
if (mTokenizer->nextToken(WHITESPACE).isEmpty()) {
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
Error:
|
||||
ALOGE("%s: Malformed character literal.", mTokenizer->getLocation().string());
|
||||
return BAD_VALUE;
|
||||
}
|
||||
|
||||
} // namespace android
|
|
@ -0,0 +1,199 @@
|
|||
/*
|
||||
* Copyright (C) 2008 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef _UI_KEY_CHARACTER_MAP_H
|
||||
#define _UI_KEY_CHARACTER_MAP_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "Input.h"
|
||||
#include <utils/Errors.h>
|
||||
#include <utils/KeyedVector.h>
|
||||
#include <utils/Tokenizer.h>
|
||||
#include <utils/String8.h>
|
||||
#include <utils/Unicode.h>
|
||||
|
||||
namespace android {
|
||||
|
||||
/**
|
||||
* Describes a mapping from Android key codes to characters.
|
||||
* Also specifies other functions of the keyboard such as the keyboard type
|
||||
* and key modifier semantics.
|
||||
*/
|
||||
class KeyCharacterMap {
|
||||
public:
|
||||
enum KeyboardType {
|
||||
KEYBOARD_TYPE_UNKNOWN = 0,
|
||||
KEYBOARD_TYPE_NUMERIC = 1,
|
||||
KEYBOARD_TYPE_PREDICTIVE = 2,
|
||||
KEYBOARD_TYPE_ALPHA = 3,
|
||||
KEYBOARD_TYPE_FULL = 4,
|
||||
KEYBOARD_TYPE_SPECIAL_FUNCTION = 5,
|
||||
};
|
||||
|
||||
// Substitute key code and meta state for fallback action.
|
||||
struct FallbackAction {
|
||||
int32_t keyCode;
|
||||
int32_t metaState;
|
||||
};
|
||||
|
||||
~KeyCharacterMap();
|
||||
|
||||
static status_t load(const String8& filename, KeyCharacterMap** outMap);
|
||||
|
||||
/* Gets the keyboard type. */
|
||||
int32_t getKeyboardType() const;
|
||||
|
||||
/* Gets the primary character for this key as in the label physically printed on it.
|
||||
* Returns 0 if none (eg. for non-printing keys). */
|
||||
char16_t getDisplayLabel(int32_t keyCode) const;
|
||||
|
||||
/* Gets the Unicode character for the number or symbol generated by the key
|
||||
* when the keyboard is used as a dialing pad.
|
||||
* Returns 0 if no number or symbol is generated.
|
||||
*/
|
||||
char16_t getNumber(int32_t keyCode) const;
|
||||
|
||||
/* Gets the Unicode character generated by the key and meta key modifiers.
|
||||
* Returns 0 if no character is generated.
|
||||
*/
|
||||
char16_t getCharacter(int32_t keyCode, int32_t metaState) const;
|
||||
|
||||
/* Gets the fallback action to use by default if the application does not
|
||||
* handle the specified key.
|
||||
* Returns true if an action was available, false if none.
|
||||
*/
|
||||
bool getFallbackAction(int32_t keyCode, int32_t metaState,
|
||||
FallbackAction* outFallbackAction) const;
|
||||
|
||||
/* Gets the first matching Unicode character that can be generated by the key,
|
||||
* preferring the one with the specified meta key modifiers.
|
||||
* Returns 0 if no matching character is generated.
|
||||
*/
|
||||
char16_t getMatch(int32_t keyCode, const char16_t* chars,
|
||||
size_t numChars, int32_t metaState) const;
|
||||
|
||||
/* Gets a sequence of key events that could plausibly generate the specified
|
||||
* character sequence. Returns false if some of the characters cannot be generated.
|
||||
*/
|
||||
bool getEvents(int32_t deviceId, const char16_t* chars, size_t numChars,
|
||||
Vector<KeyEvent>& outEvents) const;
|
||||
|
||||
private:
|
||||
struct Behavior {
|
||||
Behavior();
|
||||
|
||||
/* The next behavior in the list, or NULL if none. */
|
||||
Behavior* next;
|
||||
|
||||
/* The meta key modifiers for this behavior. */
|
||||
int32_t metaState;
|
||||
|
||||
/* The character to insert. */
|
||||
char16_t character;
|
||||
|
||||
/* The fallback keycode if the key is not handled. */
|
||||
int32_t fallbackKeyCode;
|
||||
};
|
||||
|
||||
struct Key {
|
||||
Key();
|
||||
~Key();
|
||||
|
||||
/* The single character label printed on the key, or 0 if none. */
|
||||
char16_t label;
|
||||
|
||||
/* The number or symbol character generated by the key, or 0 if none. */
|
||||
char16_t number;
|
||||
|
||||
/* The list of key behaviors sorted from most specific to least specific
|
||||
* meta key binding. */
|
||||
Behavior* firstBehavior;
|
||||
};
|
||||
|
||||
class Parser {
|
||||
enum State {
|
||||
STATE_TOP = 0,
|
||||
STATE_KEY = 1,
|
||||
};
|
||||
|
||||
enum {
|
||||
PROPERTY_LABEL = 1,
|
||||
PROPERTY_NUMBER = 2,
|
||||
PROPERTY_META = 3,
|
||||
};
|
||||
|
||||
struct Property {
|
||||
inline Property(int32_t property = 0, int32_t metaState = 0) :
|
||||
property(property), metaState(metaState) { }
|
||||
|
||||
int32_t property;
|
||||
int32_t metaState;
|
||||
};
|
||||
|
||||
KeyCharacterMap* mMap;
|
||||
Tokenizer* mTokenizer;
|
||||
State mState;
|
||||
int32_t mKeyCode;
|
||||
|
||||
public:
|
||||
Parser(KeyCharacterMap* map, Tokenizer* tokenizer);
|
||||
~Parser();
|
||||
status_t parse();
|
||||
|
||||
private:
|
||||
status_t parseType();
|
||||
status_t parseKey();
|
||||
status_t parseKeyProperty();
|
||||
status_t parseModifier(const String8& token, int32_t* outMetaState);
|
||||
status_t parseCharacterLiteral(char16_t* outCharacter);
|
||||
};
|
||||
|
||||
KeyedVector<int32_t, Key*> mKeys;
|
||||
int mType;
|
||||
|
||||
KeyCharacterMap();
|
||||
|
||||
bool getKey(int32_t keyCode, const Key** outKey) const;
|
||||
bool getKeyBehavior(int32_t keyCode, int32_t metaState,
|
||||
const Key** outKey, const Behavior** outBehavior) const;
|
||||
|
||||
bool findKey(char16_t ch, int32_t* outKeyCode, int32_t* outMetaState) const;
|
||||
|
||||
static void addKey(Vector<KeyEvent>& outEvents,
|
||||
int32_t deviceId, int32_t keyCode, int32_t metaState, bool down, nsecs_t time);
|
||||
static void addMetaKeys(Vector<KeyEvent>& outEvents,
|
||||
int32_t deviceId, int32_t metaState, bool down, nsecs_t time,
|
||||
int32_t* currentMetaState);
|
||||
static bool addSingleEphemeralMetaKey(Vector<KeyEvent>& outEvents,
|
||||
int32_t deviceId, int32_t metaState, bool down, nsecs_t time,
|
||||
int32_t keyCode, int32_t keyMetaState,
|
||||
int32_t* currentMetaState);
|
||||
static void addDoubleEphemeralMetaKey(Vector<KeyEvent>& outEvents,
|
||||
int32_t deviceId, int32_t metaState, bool down, nsecs_t time,
|
||||
int32_t leftKeyCode, int32_t leftKeyMetaState,
|
||||
int32_t rightKeyCode, int32_t rightKeyMetaState,
|
||||
int32_t eitherKeyMetaState,
|
||||
int32_t* currentMetaState);
|
||||
static void addLockedMetaKey(Vector<KeyEvent>& outEvents,
|
||||
int32_t deviceId, int32_t metaState, nsecs_t time,
|
||||
int32_t keyCode, int32_t keyMetaState,
|
||||
int32_t* currentMetaState);
|
||||
};
|
||||
|
||||
} // namespace android
|
||||
|
||||
#endif // _UI_KEY_CHARACTER_MAP_H
|
|
@ -0,0 +1,341 @@
|
|||
/*
|
||||
* Copyright (C) 2008 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#define LOG_TAG "KeyLayoutMap"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <android/keycodes.h>
|
||||
#include "Keyboard.h"
|
||||
#include "KeyLayoutMap.h"
|
||||
#include <utils/Log.h>
|
||||
#include <utils/Errors.h>
|
||||
#include <utils/Tokenizer.h>
|
||||
#include <utils/Timers.h>
|
||||
|
||||
// Enables debug output for the parser.
|
||||
#define DEBUG_PARSER 0
|
||||
|
||||
// Enables debug output for parser performance.
|
||||
#define DEBUG_PARSER_PERFORMANCE 0
|
||||
|
||||
// Enables debug output for mapping.
|
||||
#define DEBUG_MAPPING 0
|
||||
|
||||
|
||||
namespace android {
|
||||
|
||||
static const char* WHITESPACE = " \t\r";
|
||||
|
||||
// --- KeyLayoutMap ---
|
||||
|
||||
KeyLayoutMap::KeyLayoutMap() {
|
||||
}
|
||||
|
||||
KeyLayoutMap::~KeyLayoutMap() {
|
||||
}
|
||||
|
||||
status_t KeyLayoutMap::load(const String8& filename, KeyLayoutMap** outMap) {
|
||||
*outMap = NULL;
|
||||
|
||||
Tokenizer* tokenizer;
|
||||
status_t status = Tokenizer::open(filename, &tokenizer);
|
||||
if (status) {
|
||||
ALOGE("Error %d opening key layout map file %s.", status, filename.string());
|
||||
} else {
|
||||
KeyLayoutMap* map = new KeyLayoutMap();
|
||||
if (!map) {
|
||||
ALOGE("Error allocating key layout map.");
|
||||
status = NO_MEMORY;
|
||||
} else {
|
||||
#if DEBUG_PARSER_PERFORMANCE
|
||||
nsecs_t startTime = systemTime(SYSTEM_TIME_MONOTONIC);
|
||||
#endif
|
||||
Parser parser(map, tokenizer);
|
||||
status = parser.parse();
|
||||
#if DEBUG_PARSER_PERFORMANCE
|
||||
nsecs_t elapsedTime = systemTime(SYSTEM_TIME_MONOTONIC) - startTime;
|
||||
ALOGD("Parsed key layout map file '%s' %d lines in %0.3fms.",
|
||||
tokenizer->getFilename().string(), tokenizer->getLineNumber(),
|
||||
elapsedTime / 1000000.0);
|
||||
#endif
|
||||
if (status) {
|
||||
delete map;
|
||||
} else {
|
||||
*outMap = map;
|
||||
}
|
||||
}
|
||||
delete tokenizer;
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
status_t KeyLayoutMap::mapKey(int32_t scanCode, int32_t* keyCode, uint32_t* flags) const {
|
||||
ssize_t index = mKeys.indexOfKey(scanCode);
|
||||
if (index < 0) {
|
||||
#if DEBUG_MAPPING
|
||||
ALOGD("mapKey: scanCode=%d ~ Failed.", scanCode);
|
||||
#endif
|
||||
*keyCode = AKEYCODE_UNKNOWN;
|
||||
*flags = 0;
|
||||
return NAME_NOT_FOUND;
|
||||
}
|
||||
|
||||
const Key& k = mKeys.valueAt(index);
|
||||
*keyCode = k.keyCode;
|
||||
*flags = k.flags;
|
||||
|
||||
#if DEBUG_MAPPING
|
||||
ALOGD("mapKey: scanCode=%d ~ Result keyCode=%d, flags=0x%08x.", scanCode, *keyCode, *flags);
|
||||
#endif
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
status_t KeyLayoutMap::findScanCodesForKey(int32_t keyCode, Vector<int32_t>* outScanCodes) const {
|
||||
const size_t N = mKeys.size();
|
||||
for (size_t i=0; i<N; i++) {
|
||||
if (mKeys.valueAt(i).keyCode == keyCode) {
|
||||
outScanCodes->add(mKeys.keyAt(i));
|
||||
}
|
||||
}
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
status_t KeyLayoutMap::mapAxis(int32_t scanCode, AxisInfo* outAxisInfo) const {
|
||||
ssize_t index = mAxes.indexOfKey(scanCode);
|
||||
if (index < 0) {
|
||||
#if DEBUG_MAPPING
|
||||
ALOGD("mapAxis: scanCode=%d ~ Failed.", scanCode);
|
||||
#endif
|
||||
return NAME_NOT_FOUND;
|
||||
}
|
||||
|
||||
*outAxisInfo = mAxes.valueAt(index);
|
||||
|
||||
#if DEBUG_MAPPING
|
||||
ALOGD("mapAxis: scanCode=%d ~ Result mode=%d, axis=%d, highAxis=%d, "
|
||||
"splitValue=%d, flatOverride=%d.",
|
||||
scanCode,
|
||||
outAxisInfo->mode, outAxisInfo->axis, outAxisInfo->highAxis,
|
||||
outAxisInfo->splitValue, outAxisInfo->flatOverride);
|
||||
#endif
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
|
||||
// --- KeyLayoutMap::Parser ---
|
||||
|
||||
KeyLayoutMap::Parser::Parser(KeyLayoutMap* map, Tokenizer* tokenizer) :
|
||||
mMap(map), mTokenizer(tokenizer) {
|
||||
}
|
||||
|
||||
KeyLayoutMap::Parser::~Parser() {
|
||||
}
|
||||
|
||||
status_t KeyLayoutMap::Parser::parse() {
|
||||
while (!mTokenizer->isEof()) {
|
||||
#if DEBUG_PARSER
|
||||
ALOGD("Parsing %s: '%s'.", mTokenizer->getLocation().string(),
|
||||
mTokenizer->peekRemainderOfLine().string());
|
||||
#endif
|
||||
|
||||
mTokenizer->skipDelimiters(WHITESPACE);
|
||||
|
||||
if (!mTokenizer->isEol() && mTokenizer->peekChar() != '#') {
|
||||
String8 keywordToken = mTokenizer->nextToken(WHITESPACE);
|
||||
if (keywordToken == "key") {
|
||||
mTokenizer->skipDelimiters(WHITESPACE);
|
||||
status_t status = parseKey();
|
||||
if (status) return status;
|
||||
} else if (keywordToken == "axis") {
|
||||
mTokenizer->skipDelimiters(WHITESPACE);
|
||||
status_t status = parseAxis();
|
||||
if (status) return status;
|
||||
} else {
|
||||
ALOGE("%s: Expected keyword, got '%s'.", mTokenizer->getLocation().string(),
|
||||
keywordToken.string());
|
||||
return BAD_VALUE;
|
||||
}
|
||||
|
||||
mTokenizer->skipDelimiters(WHITESPACE);
|
||||
if (!mTokenizer->isEol()) {
|
||||
ALOGE("%s: Expected end of line, got '%s'.",
|
||||
mTokenizer->getLocation().string(),
|
||||
mTokenizer->peekRemainderOfLine().string());
|
||||
return BAD_VALUE;
|
||||
}
|
||||
}
|
||||
|
||||
mTokenizer->nextLine();
|
||||
}
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
status_t KeyLayoutMap::Parser::parseKey() {
|
||||
String8 scanCodeToken = mTokenizer->nextToken(WHITESPACE);
|
||||
char* end;
|
||||
int32_t scanCode = int32_t(strtol(scanCodeToken.string(), &end, 0));
|
||||
if (*end) {
|
||||
ALOGE("%s: Expected key scan code number, got '%s'.", mTokenizer->getLocation().string(),
|
||||
scanCodeToken.string());
|
||||
return BAD_VALUE;
|
||||
}
|
||||
if (mMap->mKeys.indexOfKey(scanCode) >= 0) {
|
||||
ALOGE("%s: Duplicate entry for key scan code '%s'.", mTokenizer->getLocation().string(),
|
||||
scanCodeToken.string());
|
||||
return BAD_VALUE;
|
||||
}
|
||||
|
||||
mTokenizer->skipDelimiters(WHITESPACE);
|
||||
String8 keyCodeToken = mTokenizer->nextToken(WHITESPACE);
|
||||
int32_t keyCode = getKeyCodeByLabel(keyCodeToken.string());
|
||||
if (!keyCode) {
|
||||
ALOGE("%s: Expected key code label, got '%s'.", mTokenizer->getLocation().string(),
|
||||
keyCodeToken.string());
|
||||
return BAD_VALUE;
|
||||
}
|
||||
|
||||
uint32_t flags = 0;
|
||||
for (;;) {
|
||||
mTokenizer->skipDelimiters(WHITESPACE);
|
||||
if (mTokenizer->isEol()) break;
|
||||
|
||||
String8 flagToken = mTokenizer->nextToken(WHITESPACE);
|
||||
uint32_t flag = getKeyFlagByLabel(flagToken.string());
|
||||
if (!flag) {
|
||||
ALOGE("%s: Expected key flag label, got '%s'.", mTokenizer->getLocation().string(),
|
||||
flagToken.string());
|
||||
return BAD_VALUE;
|
||||
}
|
||||
if (flags & flag) {
|
||||
ALOGE("%s: Duplicate key flag '%s'.", mTokenizer->getLocation().string(),
|
||||
flagToken.string());
|
||||
return BAD_VALUE;
|
||||
}
|
||||
flags |= flag;
|
||||
}
|
||||
|
||||
#if DEBUG_PARSER
|
||||
ALOGD("Parsed key: scanCode=%d, keyCode=%d, flags=0x%08x.", scanCode, keyCode, flags);
|
||||
#endif
|
||||
Key key;
|
||||
key.keyCode = keyCode;
|
||||
key.flags = flags;
|
||||
mMap->mKeys.add(scanCode, key);
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
status_t KeyLayoutMap::Parser::parseAxis() {
|
||||
String8 scanCodeToken = mTokenizer->nextToken(WHITESPACE);
|
||||
char* end;
|
||||
int32_t scanCode = int32_t(strtol(scanCodeToken.string(), &end, 0));
|
||||
if (*end) {
|
||||
ALOGE("%s: Expected axis scan code number, got '%s'.", mTokenizer->getLocation().string(),
|
||||
scanCodeToken.string());
|
||||
return BAD_VALUE;
|
||||
}
|
||||
if (mMap->mAxes.indexOfKey(scanCode) >= 0) {
|
||||
ALOGE("%s: Duplicate entry for axis scan code '%s'.", mTokenizer->getLocation().string(),
|
||||
scanCodeToken.string());
|
||||
return BAD_VALUE;
|
||||
}
|
||||
|
||||
AxisInfo axisInfo;
|
||||
|
||||
mTokenizer->skipDelimiters(WHITESPACE);
|
||||
String8 token = mTokenizer->nextToken(WHITESPACE);
|
||||
if (token == "invert") {
|
||||
axisInfo.mode = AxisInfo::MODE_INVERT;
|
||||
|
||||
mTokenizer->skipDelimiters(WHITESPACE);
|
||||
String8 axisToken = mTokenizer->nextToken(WHITESPACE);
|
||||
axisInfo.axis = getAxisByLabel(axisToken.string());
|
||||
if (axisInfo.axis < 0) {
|
||||
ALOGE("%s: Expected inverted axis label, got '%s'.",
|
||||
mTokenizer->getLocation().string(), axisToken.string());
|
||||
return BAD_VALUE;
|
||||
}
|
||||
} else if (token == "split") {
|
||||
axisInfo.mode = AxisInfo::MODE_SPLIT;
|
||||
|
||||
mTokenizer->skipDelimiters(WHITESPACE);
|
||||
String8 splitToken = mTokenizer->nextToken(WHITESPACE);
|
||||
axisInfo.splitValue = int32_t(strtol(splitToken.string(), &end, 0));
|
||||
if (*end) {
|
||||
ALOGE("%s: Expected split value, got '%s'.",
|
||||
mTokenizer->getLocation().string(), splitToken.string());
|
||||
return BAD_VALUE;
|
||||
}
|
||||
|
||||
mTokenizer->skipDelimiters(WHITESPACE);
|
||||
String8 lowAxisToken = mTokenizer->nextToken(WHITESPACE);
|
||||
axisInfo.axis = getAxisByLabel(lowAxisToken.string());
|
||||
if (axisInfo.axis < 0) {
|
||||
ALOGE("%s: Expected low axis label, got '%s'.",
|
||||
mTokenizer->getLocation().string(), lowAxisToken.string());
|
||||
return BAD_VALUE;
|
||||
}
|
||||
|
||||
mTokenizer->skipDelimiters(WHITESPACE);
|
||||
String8 highAxisToken = mTokenizer->nextToken(WHITESPACE);
|
||||
axisInfo.highAxis = getAxisByLabel(highAxisToken.string());
|
||||
if (axisInfo.highAxis < 0) {
|
||||
ALOGE("%s: Expected high axis label, got '%s'.",
|
||||
mTokenizer->getLocation().string(), highAxisToken.string());
|
||||
return BAD_VALUE;
|
||||
}
|
||||
} else {
|
||||
axisInfo.axis = getAxisByLabel(token.string());
|
||||
if (axisInfo.axis < 0) {
|
||||
ALOGE("%s: Expected axis label, 'split' or 'invert', got '%s'.",
|
||||
mTokenizer->getLocation().string(), token.string());
|
||||
return BAD_VALUE;
|
||||
}
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
mTokenizer->skipDelimiters(WHITESPACE);
|
||||
if (mTokenizer->isEol()) {
|
||||
break;
|
||||
}
|
||||
String8 keywordToken = mTokenizer->nextToken(WHITESPACE);
|
||||
if (keywordToken == "flat") {
|
||||
mTokenizer->skipDelimiters(WHITESPACE);
|
||||
String8 flatToken = mTokenizer->nextToken(WHITESPACE);
|
||||
axisInfo.flatOverride = int32_t(strtol(flatToken.string(), &end, 0));
|
||||
if (*end) {
|
||||
ALOGE("%s: Expected flat value, got '%s'.",
|
||||
mTokenizer->getLocation().string(), flatToken.string());
|
||||
return BAD_VALUE;
|
||||
}
|
||||
} else {
|
||||
ALOGE("%s: Expected keyword 'flat', got '%s'.",
|
||||
mTokenizer->getLocation().string(), keywordToken.string());
|
||||
return BAD_VALUE;
|
||||
}
|
||||
}
|
||||
|
||||
#if DEBUG_PARSER
|
||||
ALOGD("Parsed axis: scanCode=%d, mode=%d, axis=%d, highAxis=%d, "
|
||||
"splitValue=%d, flatOverride=%d.",
|
||||
scanCode,
|
||||
axisInfo.mode, axisInfo.axis, axisInfo.highAxis,
|
||||
axisInfo.splitValue, axisInfo.flatOverride);
|
||||
#endif
|
||||
mMap->mAxes.add(scanCode, axisInfo);
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
};
|
|
@ -0,0 +1,99 @@
|
|||
/*
|
||||
* Copyright (C) 2008 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef _UI_KEY_LAYOUT_MAP_H
|
||||
#define _UI_KEY_LAYOUT_MAP_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <utils/Errors.h>
|
||||
#include <utils/KeyedVector.h>
|
||||
#include <utils/Tokenizer.h>
|
||||
|
||||
namespace android {
|
||||
|
||||
struct AxisInfo {
|
||||
enum Mode {
|
||||
// Axis value is reported directly.
|
||||
MODE_NORMAL = 0,
|
||||
// Axis value should be inverted before reporting.
|
||||
MODE_INVERT = 1,
|
||||
// Axis value should be split into two axes
|
||||
MODE_SPLIT = 2,
|
||||
};
|
||||
|
||||
// Axis mode.
|
||||
Mode mode;
|
||||
|
||||
// Axis id.
|
||||
// When split, this is the axis used for values smaller than the split position.
|
||||
int32_t axis;
|
||||
|
||||
// When split, this is the axis used for values after higher than the split position.
|
||||
int32_t highAxis;
|
||||
|
||||
// The split value, or 0 if not split.
|
||||
int32_t splitValue;
|
||||
|
||||
// The flat value, or -1 if none.
|
||||
int32_t flatOverride;
|
||||
|
||||
AxisInfo() : mode(MODE_NORMAL), axis(-1), highAxis(-1), splitValue(0), flatOverride(-1) {
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Describes a mapping from keyboard scan codes and joystick axes to Android key codes and axes.
|
||||
*/
|
||||
class KeyLayoutMap {
|
||||
public:
|
||||
~KeyLayoutMap();
|
||||
|
||||
static status_t load(const String8& filename, KeyLayoutMap** outMap);
|
||||
|
||||
status_t mapKey(int32_t scanCode, int32_t* keyCode, uint32_t* flags) const;
|
||||
status_t findScanCodesForKey(int32_t keyCode, Vector<int32_t>* outScanCodes) const;
|
||||
|
||||
status_t mapAxis(int32_t scanCode, AxisInfo* outAxisInfo) const;
|
||||
|
||||
private:
|
||||
struct Key {
|
||||
int32_t keyCode;
|
||||
uint32_t flags;
|
||||
};
|
||||
|
||||
KeyedVector<int32_t, Key> mKeys;
|
||||
KeyedVector<int32_t, AxisInfo> mAxes;
|
||||
|
||||
KeyLayoutMap();
|
||||
|
||||
class Parser {
|
||||
KeyLayoutMap* mMap;
|
||||
Tokenizer* mTokenizer;
|
||||
|
||||
public:
|
||||
Parser(KeyLayoutMap* map, Tokenizer* tokenizer);
|
||||
~Parser();
|
||||
status_t parse();
|
||||
|
||||
private:
|
||||
status_t parseKey();
|
||||
status_t parseAxis();
|
||||
};
|
||||
};
|
||||
|
||||
} // namespace android
|
||||
|
||||
#endif // _UI_KEY_LAYOUT_MAP_H
|
|
@ -0,0 +1,303 @@
|
|||
/*
|
||||
* Copyright (C) 2010 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#define LOG_TAG "Keyboard"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <limits.h>
|
||||
|
||||
#include "Keyboard.h"
|
||||
#include "KeycodeLabels.h"
|
||||
#include "KeyLayoutMap.h"
|
||||
#include "KeyCharacterMap.h"
|
||||
#include <utils/Errors.h>
|
||||
#include <utils/Log.h>
|
||||
#include <cutils/properties.h>
|
||||
|
||||
namespace android {
|
||||
|
||||
// --- KeyMap ---
|
||||
|
||||
KeyMap::KeyMap() :
|
||||
keyLayoutMap(NULL), keyCharacterMap(NULL) {
|
||||
}
|
||||
|
||||
KeyMap::~KeyMap() {
|
||||
delete keyLayoutMap;
|
||||
delete keyCharacterMap;
|
||||
}
|
||||
|
||||
status_t KeyMap::load(const InputDeviceIdentifier& deviceIdenfifier,
|
||||
const PropertyMap* deviceConfiguration) {
|
||||
// Use the configured key layout if available.
|
||||
if (deviceConfiguration) {
|
||||
String8 keyLayoutName;
|
||||
if (deviceConfiguration->tryGetProperty(String8("keyboard.layout"),
|
||||
keyLayoutName)) {
|
||||
status_t status = loadKeyLayout(deviceIdenfifier, keyLayoutName);
|
||||
if (status == NAME_NOT_FOUND) {
|
||||
ALOGE("Configuration for keyboard device '%s' requested keyboard layout '%s' but "
|
||||
"it was not found.",
|
||||
deviceIdenfifier.name.string(), keyLayoutName.string());
|
||||
}
|
||||
}
|
||||
|
||||
String8 keyCharacterMapName;
|
||||
if (deviceConfiguration->tryGetProperty(String8("keyboard.characterMap"),
|
||||
keyCharacterMapName)) {
|
||||
status_t status = loadKeyCharacterMap(deviceIdenfifier, keyCharacterMapName);
|
||||
if (status == NAME_NOT_FOUND) {
|
||||
ALOGE("Configuration for keyboard device '%s' requested keyboard character "
|
||||
"map '%s' but it was not found.",
|
||||
deviceIdenfifier.name.string(), keyLayoutName.string());
|
||||
}
|
||||
}
|
||||
|
||||
if (isComplete()) {
|
||||
return OK;
|
||||
}
|
||||
}
|
||||
|
||||
// Try searching by device identifier.
|
||||
if (probeKeyMap(deviceIdenfifier, String8::empty())) {
|
||||
return OK;
|
||||
}
|
||||
|
||||
// Fall back on the Generic key map.
|
||||
// TODO Apply some additional heuristics here to figure out what kind of
|
||||
// generic key map to use (US English, etc.) for typical external keyboards.
|
||||
if (probeKeyMap(deviceIdenfifier, String8("Generic"))) {
|
||||
return OK;
|
||||
}
|
||||
|
||||
// Try the Virtual key map as a last resort.
|
||||
if (probeKeyMap(deviceIdenfifier, String8("Virtual"))) {
|
||||
return OK;
|
||||
}
|
||||
|
||||
// Give up!
|
||||
ALOGE("Could not determine key map for device '%s' and no default key maps were found!",
|
||||
deviceIdenfifier.name.string());
|
||||
return NAME_NOT_FOUND;
|
||||
}
|
||||
|
||||
bool KeyMap::probeKeyMap(const InputDeviceIdentifier& deviceIdentifier,
|
||||
const String8& keyMapName) {
|
||||
if (!haveKeyLayout()) {
|
||||
loadKeyLayout(deviceIdentifier, keyMapName);
|
||||
}
|
||||
if (!haveKeyCharacterMap()) {
|
||||
loadKeyCharacterMap(deviceIdentifier, keyMapName);
|
||||
}
|
||||
return isComplete();
|
||||
}
|
||||
|
||||
status_t KeyMap::loadKeyLayout(const InputDeviceIdentifier& deviceIdentifier,
|
||||
const String8& name) {
|
||||
String8 path(getPath(deviceIdentifier, name,
|
||||
INPUT_DEVICE_CONFIGURATION_FILE_TYPE_KEY_LAYOUT));
|
||||
if (path.isEmpty()) {
|
||||
return NAME_NOT_FOUND;
|
||||
}
|
||||
|
||||
KeyLayoutMap* map;
|
||||
status_t status = KeyLayoutMap::load(path, &map);
|
||||
if (status) {
|
||||
return status;
|
||||
}
|
||||
|
||||
keyLayoutFile.setTo(path);
|
||||
keyLayoutMap = map;
|
||||
return OK;
|
||||
}
|
||||
|
||||
status_t KeyMap::loadKeyCharacterMap(const InputDeviceIdentifier& deviceIdentifier,
|
||||
const String8& name) {
|
||||
String8 path(getPath(deviceIdentifier, name,
|
||||
INPUT_DEVICE_CONFIGURATION_FILE_TYPE_KEY_CHARACTER_MAP));
|
||||
if (path.isEmpty()) {
|
||||
return NAME_NOT_FOUND;
|
||||
}
|
||||
|
||||
KeyCharacterMap* map;
|
||||
status_t status = KeyCharacterMap::load(path, &map);
|
||||
if (status) {
|
||||
return status;
|
||||
}
|
||||
|
||||
keyCharacterMapFile.setTo(path);
|
||||
keyCharacterMap = map;
|
||||
return OK;
|
||||
}
|
||||
|
||||
String8 KeyMap::getPath(const InputDeviceIdentifier& deviceIdentifier,
|
||||
const String8& name, InputDeviceConfigurationFileType type) {
|
||||
return name.isEmpty()
|
||||
? getInputDeviceConfigurationFilePathByDeviceIdentifier(deviceIdentifier, type)
|
||||
: getInputDeviceConfigurationFilePathByName(name, type);
|
||||
}
|
||||
|
||||
|
||||
// --- Global functions ---
|
||||
|
||||
bool isEligibleBuiltInKeyboard(const InputDeviceIdentifier& deviceIdentifier,
|
||||
const PropertyMap* deviceConfiguration, const KeyMap* keyMap) {
|
||||
if (!keyMap->haveKeyCharacterMap()
|
||||
|| keyMap->keyCharacterMap->getKeyboardType()
|
||||
== KeyCharacterMap::KEYBOARD_TYPE_SPECIAL_FUNCTION) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (deviceConfiguration) {
|
||||
bool builtIn = false;
|
||||
if (deviceConfiguration->tryGetProperty(String8("keyboard.builtIn"), builtIn)
|
||||
&& builtIn) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return strstr(deviceIdentifier.name.string(), "-keypad");
|
||||
}
|
||||
|
||||
static int lookupValueByLabel(const char* literal, const KeycodeLabel *list) {
|
||||
while (list->literal) {
|
||||
if (strcmp(literal, list->literal) == 0) {
|
||||
return list->value;
|
||||
}
|
||||
list++;
|
||||
}
|
||||
return list->value;
|
||||
}
|
||||
|
||||
static const char* lookupLabelByValue(int value, const KeycodeLabel *list) {
|
||||
while (list->literal) {
|
||||
if (list->value == value) {
|
||||
return list->literal;
|
||||
}
|
||||
list++;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int32_t getKeyCodeByLabel(const char* label) {
|
||||
return int32_t(lookupValueByLabel(label, KEYCODES));
|
||||
}
|
||||
|
||||
uint32_t getKeyFlagByLabel(const char* label) {
|
||||
return uint32_t(lookupValueByLabel(label, FLAGS));
|
||||
}
|
||||
|
||||
int32_t getAxisByLabel(const char* label) {
|
||||
return int32_t(lookupValueByLabel(label, AXES));
|
||||
}
|
||||
|
||||
const char* getAxisLabel(int32_t axisId) {
|
||||
return lookupLabelByValue(axisId, AXES);
|
||||
}
|
||||
|
||||
static int32_t setEphemeralMetaState(int32_t mask, bool down, int32_t oldMetaState) {
|
||||
int32_t newMetaState;
|
||||
if (down) {
|
||||
newMetaState = oldMetaState | mask;
|
||||
} else {
|
||||
newMetaState = oldMetaState &
|
||||
~(mask | AMETA_ALT_ON | AMETA_SHIFT_ON | AMETA_CTRL_ON | AMETA_META_ON);
|
||||
}
|
||||
|
||||
if (newMetaState & (AMETA_ALT_LEFT_ON | AMETA_ALT_RIGHT_ON)) {
|
||||
newMetaState |= AMETA_ALT_ON;
|
||||
}
|
||||
|
||||
if (newMetaState & (AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_RIGHT_ON)) {
|
||||
newMetaState |= AMETA_SHIFT_ON;
|
||||
}
|
||||
|
||||
if (newMetaState & (AMETA_CTRL_LEFT_ON | AMETA_CTRL_RIGHT_ON)) {
|
||||
newMetaState |= AMETA_CTRL_ON;
|
||||
}
|
||||
|
||||
if (newMetaState & (AMETA_META_LEFT_ON | AMETA_META_RIGHT_ON)) {
|
||||
newMetaState |= AMETA_META_ON;
|
||||
}
|
||||
return newMetaState;
|
||||
}
|
||||
|
||||
static int32_t toggleLockedMetaState(int32_t mask, bool down, int32_t oldMetaState) {
|
||||
if (down) {
|
||||
return oldMetaState;
|
||||
} else {
|
||||
return oldMetaState ^ mask;
|
||||
}
|
||||
}
|
||||
|
||||
int32_t updateMetaState(int32_t keyCode, bool down, int32_t oldMetaState) {
|
||||
int32_t mask;
|
||||
switch (keyCode) {
|
||||
case AKEYCODE_ALT_LEFT:
|
||||
return setEphemeralMetaState(AMETA_ALT_LEFT_ON, down, oldMetaState);
|
||||
case AKEYCODE_ALT_RIGHT:
|
||||
return setEphemeralMetaState(AMETA_ALT_RIGHT_ON, down, oldMetaState);
|
||||
case AKEYCODE_SHIFT_LEFT:
|
||||
return setEphemeralMetaState(AMETA_SHIFT_LEFT_ON, down, oldMetaState);
|
||||
case AKEYCODE_SHIFT_RIGHT:
|
||||
return setEphemeralMetaState(AMETA_SHIFT_RIGHT_ON, down, oldMetaState);
|
||||
case AKEYCODE_SYM:
|
||||
return setEphemeralMetaState(AMETA_SYM_ON, down, oldMetaState);
|
||||
case AKEYCODE_FUNCTION:
|
||||
return setEphemeralMetaState(AMETA_FUNCTION_ON, down, oldMetaState);
|
||||
case AKEYCODE_CTRL_LEFT:
|
||||
return setEphemeralMetaState(AMETA_CTRL_LEFT_ON, down, oldMetaState);
|
||||
case AKEYCODE_CTRL_RIGHT:
|
||||
return setEphemeralMetaState(AMETA_CTRL_RIGHT_ON, down, oldMetaState);
|
||||
case AKEYCODE_META_LEFT:
|
||||
return setEphemeralMetaState(AMETA_META_LEFT_ON, down, oldMetaState);
|
||||
case AKEYCODE_META_RIGHT:
|
||||
return setEphemeralMetaState(AMETA_META_RIGHT_ON, down, oldMetaState);
|
||||
case AKEYCODE_CAPS_LOCK:
|
||||
return toggleLockedMetaState(AMETA_CAPS_LOCK_ON, down, oldMetaState);
|
||||
case AKEYCODE_NUM_LOCK:
|
||||
return toggleLockedMetaState(AMETA_NUM_LOCK_ON, down, oldMetaState);
|
||||
case AKEYCODE_SCROLL_LOCK:
|
||||
return toggleLockedMetaState(AMETA_SCROLL_LOCK_ON, down, oldMetaState);
|
||||
default:
|
||||
return oldMetaState;
|
||||
}
|
||||
}
|
||||
|
||||
bool isMetaKey(int32_t keyCode) {
|
||||
switch (keyCode) {
|
||||
case AKEYCODE_ALT_LEFT:
|
||||
case AKEYCODE_ALT_RIGHT:
|
||||
case AKEYCODE_SHIFT_LEFT:
|
||||
case AKEYCODE_SHIFT_RIGHT:
|
||||
case AKEYCODE_SYM:
|
||||
case AKEYCODE_FUNCTION:
|
||||
case AKEYCODE_CTRL_LEFT:
|
||||
case AKEYCODE_CTRL_RIGHT:
|
||||
case AKEYCODE_META_LEFT:
|
||||
case AKEYCODE_META_RIGHT:
|
||||
case AKEYCODE_CAPS_LOCK:
|
||||
case AKEYCODE_NUM_LOCK:
|
||||
case AKEYCODE_SCROLL_LOCK:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
} // namespace android
|
|
@ -0,0 +1,119 @@
|
|||
/*
|
||||
* Copyright (C) 2010 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef _UI_KEYBOARD_H
|
||||
#define _UI_KEYBOARD_H
|
||||
|
||||
#include "Input.h"
|
||||
#include <utils/Errors.h>
|
||||
#include <utils/String8.h>
|
||||
#include <utils/PropertyMap.h>
|
||||
|
||||
namespace android {
|
||||
|
||||
enum {
|
||||
/* Device id of the built in keyboard. */
|
||||
DEVICE_ID_BUILT_IN_KEYBOARD = 0,
|
||||
|
||||
/* Device id of a generic virtual keyboard with a full layout that can be used
|
||||
* to synthesize key events. */
|
||||
DEVICE_ID_VIRTUAL_KEYBOARD = -1,
|
||||
};
|
||||
|
||||
class KeyLayoutMap;
|
||||
class KeyCharacterMap;
|
||||
|
||||
/**
|
||||
* Loads the key layout map and key character map for a keyboard device.
|
||||
*/
|
||||
class KeyMap {
|
||||
public:
|
||||
String8 keyLayoutFile;
|
||||
KeyLayoutMap* keyLayoutMap;
|
||||
|
||||
String8 keyCharacterMapFile;
|
||||
KeyCharacterMap* keyCharacterMap;
|
||||
|
||||
KeyMap();
|
||||
~KeyMap();
|
||||
|
||||
status_t load(const InputDeviceIdentifier& deviceIdenfier,
|
||||
const PropertyMap* deviceConfiguration);
|
||||
|
||||
inline bool haveKeyLayout() const {
|
||||
return !keyLayoutFile.isEmpty();
|
||||
}
|
||||
|
||||
inline bool haveKeyCharacterMap() const {
|
||||
return !keyCharacterMapFile.isEmpty();
|
||||
}
|
||||
|
||||
inline bool isComplete() const {
|
||||
return haveKeyLayout() && haveKeyCharacterMap();
|
||||
}
|
||||
|
||||
private:
|
||||
bool probeKeyMap(const InputDeviceIdentifier& deviceIdentifier, const String8& name);
|
||||
status_t loadKeyLayout(const InputDeviceIdentifier& deviceIdentifier, const String8& name);
|
||||
status_t loadKeyCharacterMap(const InputDeviceIdentifier& deviceIdentifier,
|
||||
const String8& name);
|
||||
String8 getPath(const InputDeviceIdentifier& deviceIdentifier,
|
||||
const String8& name, InputDeviceConfigurationFileType type);
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns true if the keyboard is eligible for use as a built-in keyboard.
|
||||
*/
|
||||
extern bool isEligibleBuiltInKeyboard(const InputDeviceIdentifier& deviceIdentifier,
|
||||
const PropertyMap* deviceConfiguration, const KeyMap* keyMap);
|
||||
|
||||
/**
|
||||
* Gets a key code by its short form label, eg. "HOME".
|
||||
* Returns 0 if unknown.
|
||||
*/
|
||||
extern int32_t getKeyCodeByLabel(const char* label);
|
||||
|
||||
/**
|
||||
* Gets a key flag by its short form label, eg. "WAKE".
|
||||
* Returns 0 if unknown.
|
||||
*/
|
||||
extern uint32_t getKeyFlagByLabel(const char* label);
|
||||
|
||||
/**
|
||||
* Gets a axis by its short form label, eg. "X".
|
||||
* Returns -1 if unknown.
|
||||
*/
|
||||
extern int32_t getAxisByLabel(const char* label);
|
||||
|
||||
/**
|
||||
* Gets a axis label by its id.
|
||||
* Returns NULL if unknown.
|
||||
*/
|
||||
extern const char* getAxisLabel(int32_t axisId);
|
||||
|
||||
/**
|
||||
* Updates a meta state field when a key is pressed or released.
|
||||
*/
|
||||
extern int32_t updateMetaState(int32_t keyCode, bool down, int32_t oldMetaState);
|
||||
|
||||
/**
|
||||
* Returns true if a key is a meta key like ALT or CAPS_LOCK.
|
||||
*/
|
||||
extern bool isMetaKey(int32_t keyCode);
|
||||
|
||||
} // namespace android
|
||||
|
||||
#endif // _UI_KEYBOARD_H
|
|
@ -0,0 +1,310 @@
|
|||
/*
|
||||
* Copyright (C) 2008 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef _UI_KEYCODE_LABELS_H
|
||||
#define _UI_KEYCODE_LABELS_H
|
||||
|
||||
#include <android/keycodes.h>
|
||||
|
||||
struct KeycodeLabel {
|
||||
const char *literal;
|
||||
int value;
|
||||
};
|
||||
|
||||
static const KeycodeLabel KEYCODES[] = {
|
||||
{ "SOFT_LEFT", 1 },
|
||||
{ "SOFT_RIGHT", 2 },
|
||||
{ "HOME", 3 },
|
||||
{ "BACK", 4 },
|
||||
{ "CALL", 5 },
|
||||
{ "ENDCALL", 6 },
|
||||
{ "0", 7 },
|
||||
{ "1", 8 },
|
||||
{ "2", 9 },
|
||||
{ "3", 10 },
|
||||
{ "4", 11 },
|
||||
{ "5", 12 },
|
||||
{ "6", 13 },
|
||||
{ "7", 14 },
|
||||
{ "8", 15 },
|
||||
{ "9", 16 },
|
||||
{ "STAR", 17 },
|
||||
{ "POUND", 18 },
|
||||
{ "DPAD_UP", 19 },
|
||||
{ "DPAD_DOWN", 20 },
|
||||
{ "DPAD_LEFT", 21 },
|
||||
{ "DPAD_RIGHT", 22 },
|
||||
{ "DPAD_CENTER", 23 },
|
||||
{ "VOLUME_UP", 24 },
|
||||
{ "VOLUME_DOWN", 25 },
|
||||
{ "POWER", 26 },
|
||||
{ "CAMERA", 27 },
|
||||
{ "CLEAR", 28 },
|
||||
{ "A", 29 },
|
||||
{ "B", 30 },
|
||||
{ "C", 31 },
|
||||
{ "D", 32 },
|
||||
{ "E", 33 },
|
||||
{ "F", 34 },
|
||||
{ "G", 35 },
|
||||
{ "H", 36 },
|
||||
{ "I", 37 },
|
||||
{ "J", 38 },
|
||||
{ "K", 39 },
|
||||
{ "L", 40 },
|
||||
{ "M", 41 },
|
||||
{ "N", 42 },
|
||||
{ "O", 43 },
|
||||
{ "P", 44 },
|
||||
{ "Q", 45 },
|
||||
{ "R", 46 },
|
||||
{ "S", 47 },
|
||||
{ "T", 48 },
|
||||
{ "U", 49 },
|
||||
{ "V", 50 },
|
||||
{ "W", 51 },
|
||||
{ "X", 52 },
|
||||
{ "Y", 53 },
|
||||
{ "Z", 54 },
|
||||
{ "COMMA", 55 },
|
||||
{ "PERIOD", 56 },
|
||||
{ "ALT_LEFT", 57 },
|
||||
{ "ALT_RIGHT", 58 },
|
||||
{ "SHIFT_LEFT", 59 },
|
||||
{ "SHIFT_RIGHT", 60 },
|
||||
{ "TAB", 61 },
|
||||
{ "SPACE", 62 },
|
||||
{ "SYM", 63 },
|
||||
{ "EXPLORER", 64 },
|
||||
{ "ENVELOPE", 65 },
|
||||
{ "ENTER", 66 },
|
||||
{ "DEL", 67 },
|
||||
{ "GRAVE", 68 },
|
||||
{ "MINUS", 69 },
|
||||
{ "EQUALS", 70 },
|
||||
{ "LEFT_BRACKET", 71 },
|
||||
{ "RIGHT_BRACKET", 72 },
|
||||
{ "BACKSLASH", 73 },
|
||||
{ "SEMICOLON", 74 },
|
||||
{ "APOSTROPHE", 75 },
|
||||
{ "SLASH", 76 },
|
||||
{ "AT", 77 },
|
||||
{ "NUM", 78 },
|
||||
{ "HEADSETHOOK", 79 },
|
||||
{ "FOCUS", 80 },
|
||||
{ "PLUS", 81 },
|
||||
{ "MENU", 82 },
|
||||
{ "NOTIFICATION", 83 },
|
||||
{ "SEARCH", 84 },
|
||||
{ "MEDIA_PLAY_PAUSE", 85 },
|
||||
{ "MEDIA_STOP", 86 },
|
||||
{ "MEDIA_NEXT", 87 },
|
||||
{ "MEDIA_PREVIOUS", 88 },
|
||||
{ "MEDIA_REWIND", 89 },
|
||||
{ "MEDIA_FAST_FORWARD", 90 },
|
||||
{ "MUTE", 91 },
|
||||
{ "PAGE_UP", 92 },
|
||||
{ "PAGE_DOWN", 93 },
|
||||
{ "PICTSYMBOLS", 94 },
|
||||
{ "SWITCH_CHARSET", 95 },
|
||||
{ "BUTTON_A", 96 },
|
||||
{ "BUTTON_B", 97 },
|
||||
{ "BUTTON_C", 98 },
|
||||
{ "BUTTON_X", 99 },
|
||||
{ "BUTTON_Y", 100 },
|
||||
{ "BUTTON_Z", 101 },
|
||||
{ "BUTTON_L1", 102 },
|
||||
{ "BUTTON_R1", 103 },
|
||||
{ "BUTTON_L2", 104 },
|
||||
{ "BUTTON_R2", 105 },
|
||||
{ "BUTTON_THUMBL", 106 },
|
||||
{ "BUTTON_THUMBR", 107 },
|
||||
{ "BUTTON_START", 108 },
|
||||
{ "BUTTON_SELECT", 109 },
|
||||
{ "BUTTON_MODE", 110 },
|
||||
{ "ESCAPE", 111 },
|
||||
{ "FORWARD_DEL", 112 },
|
||||
{ "CTRL_LEFT", 113 },
|
||||
{ "CTRL_RIGHT", 114 },
|
||||
{ "CAPS_LOCK", 115 },
|
||||
{ "SCROLL_LOCK", 116 },
|
||||
{ "META_LEFT", 117 },
|
||||
{ "META_RIGHT", 118 },
|
||||
{ "FUNCTION", 119 },
|
||||
{ "SYSRQ", 120 },
|
||||
{ "BREAK", 121 },
|
||||
{ "MOVE_HOME", 122 },
|
||||
{ "MOVE_END", 123 },
|
||||
{ "INSERT", 124 },
|
||||
{ "FORWARD", 125 },
|
||||
{ "MEDIA_PLAY", 126 },
|
||||
{ "MEDIA_PAUSE", 127 },
|
||||
{ "MEDIA_CLOSE", 128 },
|
||||
{ "MEDIA_EJECT", 129 },
|
||||
{ "MEDIA_RECORD", 130 },
|
||||
{ "F1", 131 },
|
||||
{ "F2", 132 },
|
||||
{ "F3", 133 },
|
||||
{ "F4", 134 },
|
||||
{ "F5", 135 },
|
||||
{ "F6", 136 },
|
||||
{ "F7", 137 },
|
||||
{ "F8", 138 },
|
||||
{ "F9", 139 },
|
||||
{ "F10", 140 },
|
||||
{ "F11", 141 },
|
||||
{ "F12", 142 },
|
||||
{ "NUM_LOCK", 143 },
|
||||
{ "NUMPAD_0", 144 },
|
||||
{ "NUMPAD_1", 145 },
|
||||
{ "NUMPAD_2", 146 },
|
||||
{ "NUMPAD_3", 147 },
|
||||
{ "NUMPAD_4", 148 },
|
||||
{ "NUMPAD_5", 149 },
|
||||
{ "NUMPAD_6", 150 },
|
||||
{ "NUMPAD_7", 151 },
|
||||
{ "NUMPAD_8", 152 },
|
||||
{ "NUMPAD_9", 153 },
|
||||
{ "NUMPAD_DIVIDE", 154 },
|
||||
{ "NUMPAD_MULTIPLY", 155 },
|
||||
{ "NUMPAD_SUBTRACT", 156 },
|
||||
{ "NUMPAD_ADD", 157 },
|
||||
{ "NUMPAD_DOT", 158 },
|
||||
{ "NUMPAD_COMMA", 159 },
|
||||
{ "NUMPAD_ENTER", 160 },
|
||||
{ "NUMPAD_EQUALS", 161 },
|
||||
{ "NUMPAD_LEFT_PAREN", 162 },
|
||||
{ "NUMPAD_RIGHT_PAREN", 163 },
|
||||
{ "VOLUME_MUTE", 164 },
|
||||
{ "INFO", 165 },
|
||||
{ "CHANNEL_UP", 166 },
|
||||
{ "CHANNEL_DOWN", 167 },
|
||||
{ "ZOOM_IN", 168 },
|
||||
{ "ZOOM_OUT", 169 },
|
||||
{ "TV", 170 },
|
||||
{ "WINDOW", 171 },
|
||||
{ "GUIDE", 172 },
|
||||
{ "DVR", 173 },
|
||||
{ "BOOKMARK", 174 },
|
||||
{ "CAPTIONS", 175 },
|
||||
{ "SETTINGS", 176 },
|
||||
{ "TV_POWER", 177 },
|
||||
{ "TV_INPUT", 178 },
|
||||
{ "STB_POWER", 179 },
|
||||
{ "STB_INPUT", 180 },
|
||||
{ "AVR_POWER", 181 },
|
||||
{ "AVR_INPUT", 182 },
|
||||
{ "PROG_RED", 183 },
|
||||
{ "PROG_GREEN", 184 },
|
||||
{ "PROG_YELLOW", 185 },
|
||||
{ "PROG_BLUE", 186 },
|
||||
{ "APP_SWITCH", 187 },
|
||||
{ "BUTTON_1", 188 },
|
||||
{ "BUTTON_2", 189 },
|
||||
{ "BUTTON_3", 190 },
|
||||
{ "BUTTON_4", 191 },
|
||||
{ "BUTTON_5", 192 },
|
||||
{ "BUTTON_6", 193 },
|
||||
{ "BUTTON_7", 194 },
|
||||
{ "BUTTON_8", 195 },
|
||||
{ "BUTTON_9", 196 },
|
||||
{ "BUTTON_10", 197 },
|
||||
{ "BUTTON_11", 198 },
|
||||
{ "BUTTON_12", 199 },
|
||||
{ "BUTTON_13", 200 },
|
||||
{ "BUTTON_14", 201 },
|
||||
{ "BUTTON_15", 202 },
|
||||
{ "BUTTON_16", 203 },
|
||||
{ "LANGUAGE_SWITCH", 204 },
|
||||
{ "MANNER_MODE", 205 },
|
||||
{ "3D_MODE", 206 },
|
||||
{ "CONTACTS", 207 },
|
||||
{ "CALENDAR", 208 },
|
||||
{ "MUSIC", 209 },
|
||||
{ "CALCULATOR", 210 },
|
||||
|
||||
// NOTE: If you add a new keycode here you must also add it to several other files.
|
||||
// Refer to frameworks/base/core/java/android/view/KeyEvent.java for the full list.
|
||||
|
||||
{ NULL, 0 }
|
||||
};
|
||||
|
||||
// NOTE: If you edit these flags, also edit policy flags in Input.h.
|
||||
static const KeycodeLabel FLAGS[] = {
|
||||
{ "WAKE", 0x00000001 },
|
||||
{ "WAKE_DROPPED", 0x00000002 },
|
||||
{ "SHIFT", 0x00000004 },
|
||||
{ "CAPS_LOCK", 0x00000008 },
|
||||
{ "ALT", 0x00000010 },
|
||||
{ "ALT_GR", 0x00000020 },
|
||||
{ "MENU", 0x00000040 },
|
||||
{ "LAUNCHER", 0x00000080 },
|
||||
{ "VIRTUAL", 0x00000100 },
|
||||
{ "FUNCTION", 0x00000200 },
|
||||
{ NULL, 0 }
|
||||
};
|
||||
|
||||
static const KeycodeLabel AXES[] = {
|
||||
{ "X", 0 },
|
||||
{ "Y", 1 },
|
||||
{ "PRESSURE", 2 },
|
||||
{ "SIZE", 3 },
|
||||
{ "TOUCH_MAJOR", 4 },
|
||||
{ "TOUCH_MINOR", 5 },
|
||||
{ "TOOL_MAJOR", 6 },
|
||||
{ "TOOL_MINOR", 7 },
|
||||
{ "ORIENTATION", 8 },
|
||||
{ "VSCROLL", 9 },
|
||||
{ "HSCROLL", 10 },
|
||||
{ "Z", 11 },
|
||||
{ "RX", 12 },
|
||||
{ "RY", 13 },
|
||||
{ "RZ", 14 },
|
||||
{ "HAT_X", 15 },
|
||||
{ "HAT_Y", 16 },
|
||||
{ "LTRIGGER", 17 },
|
||||
{ "RTRIGGER", 18 },
|
||||
{ "THROTTLE", 19 },
|
||||
{ "RUDDER", 20 },
|
||||
{ "WHEEL", 21 },
|
||||
{ "GAS", 22 },
|
||||
{ "BRAKE", 23 },
|
||||
{ "DISTANCE", 24 },
|
||||
{ "TILT", 25 },
|
||||
{ "GENERIC_1", 32 },
|
||||
{ "GENERIC_2", 33 },
|
||||
{ "GENERIC_3", 34 },
|
||||
{ "GENERIC_4", 35 },
|
||||
{ "GENERIC_5", 36 },
|
||||
{ "GENERIC_6", 37 },
|
||||
{ "GENERIC_7", 38 },
|
||||
{ "GENERIC_8", 39 },
|
||||
{ "GENERIC_9", 40 },
|
||||
{ "GENERIC_10", 41 },
|
||||
{ "GENERIC_11", 42 },
|
||||
{ "GENERIC_12", 43 },
|
||||
{ "GENERIC_13", 44 },
|
||||
{ "GENERIC_14", 45 },
|
||||
{ "GENERIC_15", 46 },
|
||||
{ "GENERIC_16", 47 },
|
||||
|
||||
// NOTE: If you add a new axis here you must also add it to several other files.
|
||||
// Refer to frameworks/base/core/java/android/view/MotionEvent.java for the full list.
|
||||
|
||||
{ NULL, -1 }
|
||||
};
|
||||
|
||||
#endif // _UI_KEYCODE_LABELS_H
|
|
@ -0,0 +1,119 @@
|
|||
/*
|
||||
* Copyright (C) 2007 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "PixelFormat.h"
|
||||
#include <pixelflinger/format.h>
|
||||
#include <hardware/hardware.h>
|
||||
|
||||
namespace android {
|
||||
|
||||
static const int COMPONENT_YUV = 0xFF;
|
||||
|
||||
size_t PixelFormatInfo::getScanlineSize(unsigned int width) const
|
||||
{
|
||||
size_t size;
|
||||
if (components == COMPONENT_YUV) {
|
||||
// YCbCr formats are different.
|
||||
size = (width * bitsPerPixel)>>3;
|
||||
} else {
|
||||
size = width * bytesPerPixel;
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
#ifdef HAVE_ANDROID_OS
|
||||
ssize_t bytesPerPixel(PixelFormat format)
|
||||
{
|
||||
PixelFormatInfo info;
|
||||
status_t err = getPixelFormatInfo(format, &info);
|
||||
return (err < 0) ? err : info.bytesPerPixel;
|
||||
}
|
||||
|
||||
ssize_t bitsPerPixel(PixelFormat format)
|
||||
{
|
||||
PixelFormatInfo info;
|
||||
status_t err = getPixelFormatInfo(format, &info);
|
||||
return (err < 0) ? err : info.bitsPerPixel;
|
||||
}
|
||||
|
||||
status_t getPixelFormatInfo(PixelFormat format, PixelFormatInfo* info)
|
||||
{
|
||||
if (format < 0)
|
||||
return BAD_VALUE;
|
||||
|
||||
if (info->version != sizeof(PixelFormatInfo))
|
||||
return INVALID_OPERATION;
|
||||
|
||||
// YUV format from the HAL are handled here
|
||||
switch (format) {
|
||||
case HAL_PIXEL_FORMAT_YCbCr_422_SP:
|
||||
case HAL_PIXEL_FORMAT_YCbCr_422_I:
|
||||
info->bitsPerPixel = 16;
|
||||
goto done;
|
||||
case HAL_PIXEL_FORMAT_YCrCb_420_SP:
|
||||
case HAL_PIXEL_FORMAT_YV12:
|
||||
info->bitsPerPixel = 12;
|
||||
done:
|
||||
info->format = format;
|
||||
info->components = COMPONENT_YUV;
|
||||
info->bytesPerPixel = 1;
|
||||
info->h_alpha = 0;
|
||||
info->l_alpha = 0;
|
||||
info->h_red = info->h_green = info->h_blue = 8;
|
||||
info->l_red = info->l_green = info->l_blue = 0;
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
size_t numEntries;
|
||||
const GGLFormat *i = gglGetPixelFormatTable(&numEntries) + format;
|
||||
bool valid = uint32_t(format) < numEntries;
|
||||
if (!valid) {
|
||||
return BAD_INDEX;
|
||||
}
|
||||
|
||||
#define COMPONENT(name) \
|
||||
case GGL_##name: info->components = PixelFormatInfo::name; break;
|
||||
|
||||
switch (i->components) {
|
||||
COMPONENT(ALPHA)
|
||||
COMPONENT(RGB)
|
||||
COMPONENT(RGBA)
|
||||
COMPONENT(LUMINANCE)
|
||||
COMPONENT(LUMINANCE_ALPHA)
|
||||
default:
|
||||
return BAD_INDEX;
|
||||
}
|
||||
|
||||
#undef COMPONENT
|
||||
|
||||
info->format = format;
|
||||
info->bytesPerPixel = i->size;
|
||||
info->bitsPerPixel = i->bitsPerPixel;
|
||||
info->h_alpha = i->ah;
|
||||
info->l_alpha = i->al;
|
||||
info->h_red = i->rh;
|
||||
info->l_red = i->rl;
|
||||
info->h_green = i->gh;
|
||||
info->l_green = i->gl;
|
||||
info->h_blue = i->bh;
|
||||
info->l_blue = i->bl;
|
||||
|
||||
return NO_ERROR;
|
||||
}
|
||||
#endif // HAVE_ANDROID_OS
|
||||
|
||||
}; // namespace android
|
||||
|
|
@ -0,0 +1,139 @@
|
|||
/*
|
||||
* Copyright (C) 2005 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
//
|
||||
|
||||
// Pixel formats used across the system.
|
||||
// These formats might not all be supported by all renderers, for instance
|
||||
// skia or SurfaceFlinger are not required to support all of these formats
|
||||
// (either as source or destination)
|
||||
|
||||
// XXX: we should consolidate these formats and skia's
|
||||
|
||||
#ifndef UI_PIXELFORMAT_H
|
||||
#define UI_PIXELFORMAT_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <sys/types.h>
|
||||
#include <utils/Errors.h>
|
||||
#include <pixelflinger/format.h>
|
||||
#include <hardware/hardware.h>
|
||||
|
||||
namespace android {
|
||||
|
||||
enum {
|
||||
//
|
||||
// these constants need to match those
|
||||
// in graphics/PixelFormat.java & pixelflinger/format.h
|
||||
//
|
||||
PIXEL_FORMAT_UNKNOWN = 0,
|
||||
PIXEL_FORMAT_NONE = 0,
|
||||
|
||||
// logical pixel formats used by the SurfaceFlinger -----------------------
|
||||
PIXEL_FORMAT_CUSTOM = -4,
|
||||
// Custom pixel-format described by a PixelFormatInfo structure
|
||||
|
||||
PIXEL_FORMAT_TRANSLUCENT = -3,
|
||||
// System chooses a format that supports translucency (many alpha bits)
|
||||
|
||||
PIXEL_FORMAT_TRANSPARENT = -2,
|
||||
// System chooses a format that supports transparency
|
||||
// (at least 1 alpha bit)
|
||||
|
||||
PIXEL_FORMAT_OPAQUE = -1,
|
||||
// System chooses an opaque format (no alpha bits required)
|
||||
|
||||
// real pixel formats supported for rendering -----------------------------
|
||||
|
||||
PIXEL_FORMAT_RGBA_8888 = HAL_PIXEL_FORMAT_RGBA_8888, // 4x8-bit RGBA
|
||||
PIXEL_FORMAT_RGBX_8888 = HAL_PIXEL_FORMAT_RGBX_8888, // 4x8-bit RGB0
|
||||
PIXEL_FORMAT_RGB_888 = HAL_PIXEL_FORMAT_RGB_888, // 3x8-bit RGB
|
||||
PIXEL_FORMAT_RGB_565 = HAL_PIXEL_FORMAT_RGB_565, // 16-bit RGB
|
||||
PIXEL_FORMAT_BGRA_8888 = HAL_PIXEL_FORMAT_BGRA_8888, // 4x8-bit BGRA
|
||||
PIXEL_FORMAT_RGBA_5551 = HAL_PIXEL_FORMAT_RGBA_5551, // 16-bit ARGB
|
||||
PIXEL_FORMAT_RGBA_4444 = HAL_PIXEL_FORMAT_RGBA_4444, // 16-bit ARGB
|
||||
PIXEL_FORMAT_A_8 = GGL_PIXEL_FORMAT_A_8, // 8-bit A
|
||||
PIXEL_FORMAT_L_8 = GGL_PIXEL_FORMAT_L_8, // 8-bit L (R=G=B=L)
|
||||
PIXEL_FORMAT_LA_88 = GGL_PIXEL_FORMAT_LA_88, // 16-bit LA
|
||||
PIXEL_FORMAT_RGB_332 = GGL_PIXEL_FORMAT_RGB_332, // 8-bit RGB
|
||||
|
||||
// New formats can be added if they're also defined in
|
||||
// pixelflinger/format.h
|
||||
};
|
||||
|
||||
typedef int32_t PixelFormat;
|
||||
|
||||
struct PixelFormatInfo
|
||||
{
|
||||
enum {
|
||||
INDEX_ALPHA = 0,
|
||||
INDEX_RED = 1,
|
||||
INDEX_GREEN = 2,
|
||||
INDEX_BLUE = 3
|
||||
};
|
||||
|
||||
enum { // components
|
||||
ALPHA = 1,
|
||||
RGB = 2,
|
||||
RGBA = 3,
|
||||
LUMINANCE = 4,
|
||||
LUMINANCE_ALPHA = 5,
|
||||
OTHER = 0xFF
|
||||
};
|
||||
|
||||
struct szinfo {
|
||||
uint8_t h;
|
||||
uint8_t l;
|
||||
};
|
||||
|
||||
inline PixelFormatInfo() : version(sizeof(PixelFormatInfo)) { }
|
||||
size_t getScanlineSize(unsigned int width) const;
|
||||
size_t getSize(size_t ci) const {
|
||||
return (ci <= 3) ? (cinfo[ci].h - cinfo[ci].l) : 0;
|
||||
}
|
||||
size_t version;
|
||||
PixelFormat format;
|
||||
size_t bytesPerPixel;
|
||||
size_t bitsPerPixel;
|
||||
union {
|
||||
szinfo cinfo[4];
|
||||
struct {
|
||||
uint8_t h_alpha;
|
||||
uint8_t l_alpha;
|
||||
uint8_t h_red;
|
||||
uint8_t l_red;
|
||||
uint8_t h_green;
|
||||
uint8_t l_green;
|
||||
uint8_t h_blue;
|
||||
uint8_t l_blue;
|
||||
};
|
||||
};
|
||||
uint8_t components;
|
||||
uint8_t reserved0[3];
|
||||
uint32_t reserved1;
|
||||
};
|
||||
|
||||
#ifdef HAVE_ANDROID_OS
|
||||
// Consider caching the results of these functions are they're not
|
||||
// guaranteed to be fast.
|
||||
ssize_t bytesPerPixel(PixelFormat format);
|
||||
ssize_t bitsPerPixel(PixelFormat format);
|
||||
status_t getPixelFormatInfo(PixelFormat format, PixelFormatInfo* info);
|
||||
#endif
|
||||
|
||||
}; // namespace android
|
||||
|
||||
#endif // UI_PIXELFORMAT_H
|
|
@ -0,0 +1,601 @@
|
|||
/*
|
||||
* Copyright (C) 2010 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#define LOG_TAG "PointerController"
|
||||
|
||||
//#define LOG_NDEBUG 0
|
||||
|
||||
// Log debug messages about pointer updates
|
||||
#define DEBUG_POINTER_UPDATES 0
|
||||
|
||||
#include "PointerController.h"
|
||||
|
||||
#include <cutils/log.h>
|
||||
|
||||
#include <SkBitmap.h>
|
||||
#include <SkCanvas.h>
|
||||
#include <SkColor.h>
|
||||
#include <SkPaint.h>
|
||||
#include <SkXfermode.h>
|
||||
|
||||
namespace android {
|
||||
|
||||
// --- PointerController ---
|
||||
|
||||
// Time to wait before starting the fade when the pointer is inactive.
|
||||
static const nsecs_t INACTIVITY_TIMEOUT_DELAY_TIME_NORMAL = 15 * 1000 * 1000000LL; // 15 seconds
|
||||
static const nsecs_t INACTIVITY_TIMEOUT_DELAY_TIME_SHORT = 3 * 1000 * 1000000LL; // 3 seconds
|
||||
|
||||
// Time to wait between animation frames.
|
||||
static const nsecs_t ANIMATION_FRAME_INTERVAL = 1000000000LL / 60;
|
||||
|
||||
// Time to spend fading out the spot completely.
|
||||
static const nsecs_t SPOT_FADE_DURATION = 200 * 1000000LL; // 200 ms
|
||||
|
||||
// Time to spend fading out the pointer completely.
|
||||
static const nsecs_t POINTER_FADE_DURATION = 500 * 1000000LL; // 500 ms
|
||||
|
||||
|
||||
// --- PointerController ---
|
||||
|
||||
PointerController::PointerController(const sp<PointerControllerPolicyInterface>& policy,
|
||||
const sp<Looper>& looper, const sp<SpriteController>& spriteController) :
|
||||
mPolicy(policy), mLooper(looper), mSpriteController(spriteController) {
|
||||
mHandler = new WeakMessageHandler(this);
|
||||
|
||||
AutoMutex _l(mLock);
|
||||
|
||||
mLocked.animationPending = false;
|
||||
|
||||
mLocked.displayWidth = -1;
|
||||
mLocked.displayHeight = -1;
|
||||
mLocked.displayOrientation = DISPLAY_ORIENTATION_0;
|
||||
|
||||
mLocked.presentation = PRESENTATION_POINTER;
|
||||
mLocked.presentationChanged = false;
|
||||
|
||||
mLocked.inactivityTimeout = INACTIVITY_TIMEOUT_NORMAL;
|
||||
|
||||
mLocked.pointerFadeDirection = 0;
|
||||
mLocked.pointerX = 0;
|
||||
mLocked.pointerY = 0;
|
||||
mLocked.pointerAlpha = 0.0f; // pointer is initially faded
|
||||
mLocked.pointerSprite = mSpriteController->createSprite();
|
||||
mLocked.pointerIconChanged = false;
|
||||
|
||||
mLocked.buttonState = 0;
|
||||
|
||||
loadResources();
|
||||
}
|
||||
|
||||
PointerController::~PointerController() {
|
||||
mLooper->removeMessages(mHandler);
|
||||
|
||||
AutoMutex _l(mLock);
|
||||
|
||||
mLocked.pointerSprite.clear();
|
||||
|
||||
for (size_t i = 0; i < mLocked.spots.size(); i++) {
|
||||
delete mLocked.spots.itemAt(i);
|
||||
}
|
||||
mLocked.spots.clear();
|
||||
mLocked.recycledSprites.clear();
|
||||
}
|
||||
|
||||
bool PointerController::getBounds(float* outMinX, float* outMinY,
|
||||
float* outMaxX, float* outMaxY) const {
|
||||
AutoMutex _l(mLock);
|
||||
|
||||
return getBoundsLocked(outMinX, outMinY, outMaxX, outMaxY);
|
||||
}
|
||||
|
||||
bool PointerController::getBoundsLocked(float* outMinX, float* outMinY,
|
||||
float* outMaxX, float* outMaxY) const {
|
||||
if (mLocked.displayWidth <= 0 || mLocked.displayHeight <= 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
*outMinX = 0;
|
||||
*outMinY = 0;
|
||||
switch (mLocked.displayOrientation) {
|
||||
case DISPLAY_ORIENTATION_90:
|
||||
case DISPLAY_ORIENTATION_270:
|
||||
*outMaxX = mLocked.displayHeight - 1;
|
||||
*outMaxY = mLocked.displayWidth - 1;
|
||||
break;
|
||||
default:
|
||||
*outMaxX = mLocked.displayWidth - 1;
|
||||
*outMaxY = mLocked.displayHeight - 1;
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void PointerController::move(float deltaX, float deltaY) {
|
||||
#if DEBUG_POINTER_UPDATES
|
||||
ALOGD("Move pointer by deltaX=%0.3f, deltaY=%0.3f", deltaX, deltaY);
|
||||
#endif
|
||||
if (deltaX == 0.0f && deltaY == 0.0f) {
|
||||
return;
|
||||
}
|
||||
|
||||
AutoMutex _l(mLock);
|
||||
|
||||
setPositionLocked(mLocked.pointerX + deltaX, mLocked.pointerY + deltaY);
|
||||
}
|
||||
|
||||
void PointerController::setButtonState(int32_t buttonState) {
|
||||
#if DEBUG_POINTER_UPDATES
|
||||
ALOGD("Set button state 0x%08x", buttonState);
|
||||
#endif
|
||||
AutoMutex _l(mLock);
|
||||
|
||||
if (mLocked.buttonState != buttonState) {
|
||||
mLocked.buttonState = buttonState;
|
||||
}
|
||||
}
|
||||
|
||||
int32_t PointerController::getButtonState() const {
|
||||
AutoMutex _l(mLock);
|
||||
|
||||
return mLocked.buttonState;
|
||||
}
|
||||
|
||||
void PointerController::setPosition(float x, float y) {
|
||||
#if DEBUG_POINTER_UPDATES
|
||||
ALOGD("Set pointer position to x=%0.3f, y=%0.3f", x, y);
|
||||
#endif
|
||||
AutoMutex _l(mLock);
|
||||
|
||||
setPositionLocked(x, y);
|
||||
}
|
||||
|
||||
void PointerController::setPositionLocked(float x, float y) {
|
||||
float minX, minY, maxX, maxY;
|
||||
if (getBoundsLocked(&minX, &minY, &maxX, &maxY)) {
|
||||
if (x <= minX) {
|
||||
mLocked.pointerX = minX;
|
||||
} else if (x >= maxX) {
|
||||
mLocked.pointerX = maxX;
|
||||
} else {
|
||||
mLocked.pointerX = x;
|
||||
}
|
||||
if (y <= minY) {
|
||||
mLocked.pointerY = minY;
|
||||
} else if (y >= maxY) {
|
||||
mLocked.pointerY = maxY;
|
||||
} else {
|
||||
mLocked.pointerY = y;
|
||||
}
|
||||
updatePointerLocked();
|
||||
}
|
||||
}
|
||||
|
||||
void PointerController::getPosition(float* outX, float* outY) const {
|
||||
AutoMutex _l(mLock);
|
||||
|
||||
*outX = mLocked.pointerX;
|
||||
*outY = mLocked.pointerY;
|
||||
}
|
||||
|
||||
void PointerController::fade(Transition transition) {
|
||||
AutoMutex _l(mLock);
|
||||
|
||||
// Remove the inactivity timeout, since we are fading now.
|
||||
removeInactivityTimeoutLocked();
|
||||
|
||||
// Start fading.
|
||||
if (transition == TRANSITION_IMMEDIATE) {
|
||||
mLocked.pointerFadeDirection = 0;
|
||||
mLocked.pointerAlpha = 0.0f;
|
||||
updatePointerLocked();
|
||||
} else {
|
||||
mLocked.pointerFadeDirection = -1;
|
||||
startAnimationLocked();
|
||||
}
|
||||
}
|
||||
|
||||
void PointerController::unfade(Transition transition) {
|
||||
AutoMutex _l(mLock);
|
||||
|
||||
// Always reset the inactivity timer.
|
||||
resetInactivityTimeoutLocked();
|
||||
|
||||
// Start unfading.
|
||||
if (transition == TRANSITION_IMMEDIATE) {
|
||||
mLocked.pointerFadeDirection = 0;
|
||||
mLocked.pointerAlpha = 1.0f;
|
||||
updatePointerLocked();
|
||||
} else {
|
||||
mLocked.pointerFadeDirection = 1;
|
||||
startAnimationLocked();
|
||||
}
|
||||
}
|
||||
|
||||
void PointerController::setPresentation(Presentation presentation) {
|
||||
AutoMutex _l(mLock);
|
||||
|
||||
if (mLocked.presentation != presentation) {
|
||||
mLocked.presentation = presentation;
|
||||
mLocked.presentationChanged = true;
|
||||
|
||||
if (presentation != PRESENTATION_SPOT) {
|
||||
fadeOutAndReleaseAllSpotsLocked();
|
||||
}
|
||||
|
||||
updatePointerLocked();
|
||||
}
|
||||
}
|
||||
|
||||
void PointerController::setSpots(const PointerCoords* spotCoords,
|
||||
const uint32_t* spotIdToIndex, BitSet32 spotIdBits) {
|
||||
#if DEBUG_POINTER_UPDATES
|
||||
ALOGD("setSpots: idBits=%08x", spotIdBits.value);
|
||||
for (BitSet32 idBits(spotIdBits); !idBits.isEmpty(); ) {
|
||||
uint32_t id = idBits.firstMarkedBit();
|
||||
idBits.clearBit(id);
|
||||
const PointerCoords& c = spotCoords[spotIdToIndex[id]];
|
||||
ALOGD(" spot %d: position=(%0.3f, %0.3f), pressure=%0.3f", id,
|
||||
c.getAxisValue(AMOTION_EVENT_AXIS_X),
|
||||
c.getAxisValue(AMOTION_EVENT_AXIS_Y),
|
||||
c.getAxisValue(AMOTION_EVENT_AXIS_PRESSURE));
|
||||
}
|
||||
#endif
|
||||
|
||||
AutoMutex _l(mLock);
|
||||
|
||||
mSpriteController->openTransaction();
|
||||
|
||||
// Add or move spots for fingers that are down.
|
||||
for (BitSet32 idBits(spotIdBits); !idBits.isEmpty(); ) {
|
||||
uint32_t id = idBits.clearFirstMarkedBit();
|
||||
const PointerCoords& c = spotCoords[spotIdToIndex[id]];
|
||||
const SpriteIcon& icon = c.getAxisValue(AMOTION_EVENT_AXIS_PRESSURE) > 0
|
||||
? mResources.spotTouch : mResources.spotHover;
|
||||
float x = c.getAxisValue(AMOTION_EVENT_AXIS_X);
|
||||
float y = c.getAxisValue(AMOTION_EVENT_AXIS_Y);
|
||||
|
||||
Spot* spot = getSpotLocked(id);
|
||||
if (!spot) {
|
||||
spot = createAndAddSpotLocked(id);
|
||||
}
|
||||
|
||||
spot->updateSprite(&icon, x, y);
|
||||
}
|
||||
|
||||
// Remove spots for fingers that went up.
|
||||
for (size_t i = 0; i < mLocked.spots.size(); i++) {
|
||||
Spot* spot = mLocked.spots.itemAt(i);
|
||||
if (spot->id != Spot::INVALID_ID
|
||||
&& !spotIdBits.hasBit(spot->id)) {
|
||||
fadeOutAndReleaseSpotLocked(spot);
|
||||
}
|
||||
}
|
||||
|
||||
mSpriteController->closeTransaction();
|
||||
}
|
||||
|
||||
void PointerController::clearSpots() {
|
||||
#if DEBUG_POINTER_UPDATES
|
||||
ALOGD("clearSpots");
|
||||
#endif
|
||||
|
||||
AutoMutex _l(mLock);
|
||||
|
||||
fadeOutAndReleaseAllSpotsLocked();
|
||||
}
|
||||
|
||||
void PointerController::setInactivityTimeout(InactivityTimeout inactivityTimeout) {
|
||||
AutoMutex _l(mLock);
|
||||
|
||||
if (mLocked.inactivityTimeout != inactivityTimeout) {
|
||||
mLocked.inactivityTimeout = inactivityTimeout;
|
||||
resetInactivityTimeoutLocked();
|
||||
}
|
||||
}
|
||||
|
||||
void PointerController::setDisplaySize(int32_t width, int32_t height) {
|
||||
AutoMutex _l(mLock);
|
||||
|
||||
if (mLocked.displayWidth != width || mLocked.displayHeight != height) {
|
||||
mLocked.displayWidth = width;
|
||||
mLocked.displayHeight = height;
|
||||
|
||||
float minX, minY, maxX, maxY;
|
||||
if (getBoundsLocked(&minX, &minY, &maxX, &maxY)) {
|
||||
mLocked.pointerX = (minX + maxX) * 0.5f;
|
||||
mLocked.pointerY = (minY + maxY) * 0.5f;
|
||||
} else {
|
||||
mLocked.pointerX = 0;
|
||||
mLocked.pointerY = 0;
|
||||
}
|
||||
|
||||
fadeOutAndReleaseAllSpotsLocked();
|
||||
updatePointerLocked();
|
||||
}
|
||||
}
|
||||
|
||||
void PointerController::setDisplayOrientation(int32_t orientation) {
|
||||
AutoMutex _l(mLock);
|
||||
|
||||
if (mLocked.displayOrientation != orientation) {
|
||||
// Apply offsets to convert from the pixel top-left corner position to the pixel center.
|
||||
// This creates an invariant frame of reference that we can easily rotate when
|
||||
// taking into account that the pointer may be located at fractional pixel offsets.
|
||||
float x = mLocked.pointerX + 0.5f;
|
||||
float y = mLocked.pointerY + 0.5f;
|
||||
float temp;
|
||||
|
||||
// Undo the previous rotation.
|
||||
switch (mLocked.displayOrientation) {
|
||||
case DISPLAY_ORIENTATION_90:
|
||||
temp = x;
|
||||
x = mLocked.displayWidth - y;
|
||||
y = temp;
|
||||
break;
|
||||
case DISPLAY_ORIENTATION_180:
|
||||
x = mLocked.displayWidth - x;
|
||||
y = mLocked.displayHeight - y;
|
||||
break;
|
||||
case DISPLAY_ORIENTATION_270:
|
||||
temp = x;
|
||||
x = y;
|
||||
y = mLocked.displayHeight - temp;
|
||||
break;
|
||||
}
|
||||
|
||||
// Perform the new rotation.
|
||||
switch (orientation) {
|
||||
case DISPLAY_ORIENTATION_90:
|
||||
temp = x;
|
||||
x = y;
|
||||
y = mLocked.displayWidth - temp;
|
||||
break;
|
||||
case DISPLAY_ORIENTATION_180:
|
||||
x = mLocked.displayWidth - x;
|
||||
y = mLocked.displayHeight - y;
|
||||
break;
|
||||
case DISPLAY_ORIENTATION_270:
|
||||
temp = x;
|
||||
x = mLocked.displayHeight - y;
|
||||
y = temp;
|
||||
break;
|
||||
}
|
||||
|
||||
// Apply offsets to convert from the pixel center to the pixel top-left corner position
|
||||
// and save the results.
|
||||
mLocked.pointerX = x - 0.5f;
|
||||
mLocked.pointerY = y - 0.5f;
|
||||
mLocked.displayOrientation = orientation;
|
||||
|
||||
updatePointerLocked();
|
||||
}
|
||||
}
|
||||
|
||||
void PointerController::setPointerIcon(const SpriteIcon& icon) {
|
||||
AutoMutex _l(mLock);
|
||||
|
||||
mLocked.pointerIcon = icon.copy();
|
||||
mLocked.pointerIconChanged = true;
|
||||
|
||||
updatePointerLocked();
|
||||
}
|
||||
|
||||
void PointerController::handleMessage(const Message& message) {
|
||||
switch (message.what) {
|
||||
case MSG_ANIMATE:
|
||||
doAnimate();
|
||||
break;
|
||||
case MSG_INACTIVITY_TIMEOUT:
|
||||
doInactivityTimeout();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void PointerController::doAnimate() {
|
||||
AutoMutex _l(mLock);
|
||||
|
||||
bool keepAnimating = false;
|
||||
mLocked.animationPending = false;
|
||||
nsecs_t frameDelay = systemTime(SYSTEM_TIME_MONOTONIC) - mLocked.animationTime;
|
||||
|
||||
// Animate pointer fade.
|
||||
if (mLocked.pointerFadeDirection < 0) {
|
||||
mLocked.pointerAlpha -= float(frameDelay) / POINTER_FADE_DURATION;
|
||||
if (mLocked.pointerAlpha <= 0.0f) {
|
||||
mLocked.pointerAlpha = 0.0f;
|
||||
mLocked.pointerFadeDirection = 0;
|
||||
} else {
|
||||
keepAnimating = true;
|
||||
}
|
||||
updatePointerLocked();
|
||||
} else if (mLocked.pointerFadeDirection > 0) {
|
||||
mLocked.pointerAlpha += float(frameDelay) / POINTER_FADE_DURATION;
|
||||
if (mLocked.pointerAlpha >= 1.0f) {
|
||||
mLocked.pointerAlpha = 1.0f;
|
||||
mLocked.pointerFadeDirection = 0;
|
||||
} else {
|
||||
keepAnimating = true;
|
||||
}
|
||||
updatePointerLocked();
|
||||
}
|
||||
|
||||
// Animate spots that are fading out and being removed.
|
||||
for (size_t i = 0; i < mLocked.spots.size(); i++) {
|
||||
Spot* spot = mLocked.spots.itemAt(i);
|
||||
if (spot->id == Spot::INVALID_ID) {
|
||||
spot->alpha -= float(frameDelay) / SPOT_FADE_DURATION;
|
||||
if (spot->alpha <= 0) {
|
||||
mLocked.spots.removeAt(i--);
|
||||
releaseSpotLocked(spot);
|
||||
} else {
|
||||
spot->sprite->setAlpha(spot->alpha);
|
||||
keepAnimating = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (keepAnimating) {
|
||||
startAnimationLocked();
|
||||
}
|
||||
}
|
||||
|
||||
void PointerController::doInactivityTimeout() {
|
||||
fade(TRANSITION_GRADUAL);
|
||||
}
|
||||
|
||||
void PointerController::startAnimationLocked() {
|
||||
if (!mLocked.animationPending) {
|
||||
mLocked.animationPending = true;
|
||||
mLocked.animationTime = systemTime(SYSTEM_TIME_MONOTONIC);
|
||||
mLooper->sendMessageDelayed(ANIMATION_FRAME_INTERVAL, mHandler, Message(MSG_ANIMATE));
|
||||
}
|
||||
}
|
||||
|
||||
void PointerController::resetInactivityTimeoutLocked() {
|
||||
mLooper->removeMessages(mHandler, MSG_INACTIVITY_TIMEOUT);
|
||||
|
||||
nsecs_t timeout = mLocked.inactivityTimeout == INACTIVITY_TIMEOUT_SHORT
|
||||
? INACTIVITY_TIMEOUT_DELAY_TIME_SHORT : INACTIVITY_TIMEOUT_DELAY_TIME_NORMAL;
|
||||
mLooper->sendMessageDelayed(timeout, mHandler, MSG_INACTIVITY_TIMEOUT);
|
||||
}
|
||||
|
||||
void PointerController::removeInactivityTimeoutLocked() {
|
||||
mLooper->removeMessages(mHandler, MSG_INACTIVITY_TIMEOUT);
|
||||
}
|
||||
|
||||
void PointerController::updatePointerLocked() {
|
||||
mSpriteController->openTransaction();
|
||||
|
||||
mLocked.pointerSprite->setLayer(Sprite::BASE_LAYER_POINTER);
|
||||
mLocked.pointerSprite->setPosition(mLocked.pointerX, mLocked.pointerY);
|
||||
|
||||
if (mLocked.pointerAlpha > 0) {
|
||||
mLocked.pointerSprite->setAlpha(mLocked.pointerAlpha);
|
||||
mLocked.pointerSprite->setVisible(true);
|
||||
} else {
|
||||
mLocked.pointerSprite->setVisible(false);
|
||||
}
|
||||
|
||||
if (mLocked.pointerIconChanged || mLocked.presentationChanged) {
|
||||
mLocked.pointerSprite->setIcon(mLocked.presentation == PRESENTATION_POINTER
|
||||
? mLocked.pointerIcon : mResources.spotAnchor);
|
||||
mLocked.pointerIconChanged = false;
|
||||
mLocked.presentationChanged = false;
|
||||
}
|
||||
|
||||
mSpriteController->closeTransaction();
|
||||
}
|
||||
|
||||
PointerController::Spot* PointerController::getSpotLocked(uint32_t id) {
|
||||
for (size_t i = 0; i < mLocked.spots.size(); i++) {
|
||||
Spot* spot = mLocked.spots.itemAt(i);
|
||||
if (spot->id == id) {
|
||||
return spot;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
PointerController::Spot* PointerController::createAndAddSpotLocked(uint32_t id) {
|
||||
// Remove spots until we have fewer than MAX_SPOTS remaining.
|
||||
while (mLocked.spots.size() >= MAX_SPOTS) {
|
||||
Spot* spot = removeFirstFadingSpotLocked();
|
||||
if (!spot) {
|
||||
spot = mLocked.spots.itemAt(0);
|
||||
mLocked.spots.removeAt(0);
|
||||
}
|
||||
releaseSpotLocked(spot);
|
||||
}
|
||||
|
||||
// Obtain a sprite from the recycled pool.
|
||||
sp<Sprite> sprite;
|
||||
if (! mLocked.recycledSprites.isEmpty()) {
|
||||
sprite = mLocked.recycledSprites.top();
|
||||
mLocked.recycledSprites.pop();
|
||||
} else {
|
||||
sprite = mSpriteController->createSprite();
|
||||
}
|
||||
|
||||
// Return the new spot.
|
||||
Spot* spot = new Spot(id, sprite);
|
||||
mLocked.spots.push(spot);
|
||||
return spot;
|
||||
}
|
||||
|
||||
PointerController::Spot* PointerController::removeFirstFadingSpotLocked() {
|
||||
for (size_t i = 0; i < mLocked.spots.size(); i++) {
|
||||
Spot* spot = mLocked.spots.itemAt(i);
|
||||
if (spot->id == Spot::INVALID_ID) {
|
||||
mLocked.spots.removeAt(i);
|
||||
return spot;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void PointerController::releaseSpotLocked(Spot* spot) {
|
||||
spot->sprite->clearIcon();
|
||||
|
||||
if (mLocked.recycledSprites.size() < MAX_RECYCLED_SPRITES) {
|
||||
mLocked.recycledSprites.push(spot->sprite);
|
||||
}
|
||||
|
||||
delete spot;
|
||||
}
|
||||
|
||||
void PointerController::fadeOutAndReleaseSpotLocked(Spot* spot) {
|
||||
if (spot->id != Spot::INVALID_ID) {
|
||||
spot->id = Spot::INVALID_ID;
|
||||
startAnimationLocked();
|
||||
}
|
||||
}
|
||||
|
||||
void PointerController::fadeOutAndReleaseAllSpotsLocked() {
|
||||
for (size_t i = 0; i < mLocked.spots.size(); i++) {
|
||||
Spot* spot = mLocked.spots.itemAt(i);
|
||||
fadeOutAndReleaseSpotLocked(spot);
|
||||
}
|
||||
}
|
||||
|
||||
void PointerController::loadResources() {
|
||||
mPolicy->loadPointerResources(&mResources);
|
||||
}
|
||||
|
||||
|
||||
// --- PointerController::Spot ---
|
||||
|
||||
void PointerController::Spot::updateSprite(const SpriteIcon* icon, float x, float y) {
|
||||
sprite->setLayer(Sprite::BASE_LAYER_SPOT + id);
|
||||
sprite->setAlpha(alpha);
|
||||
sprite->setTransformationMatrix(SpriteTransformationMatrix(scale, 0.0f, 0.0f, scale));
|
||||
sprite->setPosition(x, y);
|
||||
|
||||
this->x = x;
|
||||
this->y = y;
|
||||
|
||||
if (icon != lastIcon) {
|
||||
lastIcon = icon;
|
||||
if (icon) {
|
||||
sprite->setIcon(*icon);
|
||||
sprite->setVisible(true);
|
||||
} else {
|
||||
sprite->setVisible(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace android
|
|
@ -0,0 +1,266 @@
|
|||
/*
|
||||
* Copyright (C) 2010 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef _UI_POINTER_CONTROLLER_H
|
||||
#define _UI_POINTER_CONTROLLER_H
|
||||
|
||||
#include "SpriteController.h"
|
||||
|
||||
#include "DisplayInfo.h"
|
||||
#include "Input.h"
|
||||
#include <utils/RefBase.h>
|
||||
#include <utils/Looper.h>
|
||||
#include <utils/String8.h>
|
||||
|
||||
#include <SkBitmap.h>
|
||||
|
||||
namespace android {
|
||||
|
||||
/**
|
||||
* Interface for tracking a mouse / touch pad pointer and touch pad spots.
|
||||
*
|
||||
* The spots are sprites on screen that visually represent the positions of
|
||||
* fingers
|
||||
*
|
||||
* The pointer controller is responsible for providing synchronization and for tracking
|
||||
* display orientation changes if needed.
|
||||
*/
|
||||
class PointerControllerInterface : public virtual RefBase {
|
||||
protected:
|
||||
PointerControllerInterface() { }
|
||||
virtual ~PointerControllerInterface() { }
|
||||
|
||||
public:
|
||||
/* Gets the bounds of the region that the pointer can traverse.
|
||||
* Returns true if the bounds are available. */
|
||||
virtual bool getBounds(float* outMinX, float* outMinY,
|
||||
float* outMaxX, float* outMaxY) const = 0;
|
||||
|
||||
/* Move the pointer. */
|
||||
virtual void move(float deltaX, float deltaY) = 0;
|
||||
|
||||
/* Sets a mask that indicates which buttons are pressed. */
|
||||
virtual void setButtonState(int32_t buttonState) = 0;
|
||||
|
||||
/* Gets a mask that indicates which buttons are pressed. */
|
||||
virtual int32_t getButtonState() const = 0;
|
||||
|
||||
/* Sets the absolute location of the pointer. */
|
||||
virtual void setPosition(float x, float y) = 0;
|
||||
|
||||
/* Gets the absolute location of the pointer. */
|
||||
virtual void getPosition(float* outX, float* outY) const = 0;
|
||||
|
||||
enum Transition {
|
||||
// Fade/unfade immediately.
|
||||
TRANSITION_IMMEDIATE,
|
||||
// Fade/unfade gradually.
|
||||
TRANSITION_GRADUAL,
|
||||
};
|
||||
|
||||
/* Fades the pointer out now. */
|
||||
virtual void fade(Transition transition) = 0;
|
||||
|
||||
/* Makes the pointer visible if it has faded out.
|
||||
* The pointer never unfades itself automatically. This method must be called
|
||||
* by the client whenever the pointer is moved or a button is pressed and it
|
||||
* wants to ensure that the pointer becomes visible again. */
|
||||
virtual void unfade(Transition transition) = 0;
|
||||
|
||||
enum Presentation {
|
||||
// Show the mouse pointer.
|
||||
PRESENTATION_POINTER,
|
||||
// Show spots and a spot anchor in place of the mouse pointer.
|
||||
PRESENTATION_SPOT,
|
||||
};
|
||||
|
||||
/* Sets the mode of the pointer controller. */
|
||||
virtual void setPresentation(Presentation presentation) = 0;
|
||||
|
||||
/* Sets the spots for the current gesture.
|
||||
* The spots are not subject to the inactivity timeout like the pointer
|
||||
* itself it since they are expected to remain visible for so long as
|
||||
* the fingers are on the touch pad.
|
||||
*
|
||||
* The values of the AMOTION_EVENT_AXIS_PRESSURE axis is significant.
|
||||
* For spotCoords, pressure != 0 indicates that the spot's location is being
|
||||
* pressed (not hovering).
|
||||
*/
|
||||
virtual void setSpots(const PointerCoords* spotCoords, const uint32_t* spotIdToIndex,
|
||||
BitSet32 spotIdBits) = 0;
|
||||
|
||||
/* Removes all spots. */
|
||||
virtual void clearSpots() = 0;
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* Pointer resources.
|
||||
*/
|
||||
struct PointerResources {
|
||||
SpriteIcon spotHover;
|
||||
SpriteIcon spotTouch;
|
||||
SpriteIcon spotAnchor;
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* Pointer controller policy interface.
|
||||
*
|
||||
* The pointer controller policy is used by the pointer controller to interact with
|
||||
* the Window Manager and other system components.
|
||||
*
|
||||
* The actual implementation is partially supported by callbacks into the DVM
|
||||
* via JNI. This interface is also mocked in the unit tests.
|
||||
*/
|
||||
class PointerControllerPolicyInterface : public virtual RefBase {
|
||||
protected:
|
||||
PointerControllerPolicyInterface() { }
|
||||
virtual ~PointerControllerPolicyInterface() { }
|
||||
|
||||
public:
|
||||
virtual void loadPointerResources(PointerResources* outResources) = 0;
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* Tracks pointer movements and draws the pointer sprite to a surface.
|
||||
*
|
||||
* Handles pointer acceleration and animation.
|
||||
*/
|
||||
class PointerController : public PointerControllerInterface, public MessageHandler {
|
||||
protected:
|
||||
virtual ~PointerController();
|
||||
|
||||
public:
|
||||
enum InactivityTimeout {
|
||||
INACTIVITY_TIMEOUT_NORMAL = 0,
|
||||
INACTIVITY_TIMEOUT_SHORT = 1,
|
||||
};
|
||||
|
||||
PointerController(const sp<PointerControllerPolicyInterface>& policy,
|
||||
const sp<Looper>& looper, const sp<SpriteController>& spriteController);
|
||||
|
||||
virtual bool getBounds(float* outMinX, float* outMinY,
|
||||
float* outMaxX, float* outMaxY) const;
|
||||
virtual void move(float deltaX, float deltaY);
|
||||
virtual void setButtonState(int32_t buttonState);
|
||||
virtual int32_t getButtonState() const;
|
||||
virtual void setPosition(float x, float y);
|
||||
virtual void getPosition(float* outX, float* outY) const;
|
||||
virtual void fade(Transition transition);
|
||||
virtual void unfade(Transition transition);
|
||||
|
||||
virtual void setPresentation(Presentation presentation);
|
||||
virtual void setSpots(const PointerCoords* spotCoords,
|
||||
const uint32_t* spotIdToIndex, BitSet32 spotIdBits);
|
||||
virtual void clearSpots();
|
||||
|
||||
void setDisplaySize(int32_t width, int32_t height);
|
||||
void setDisplayOrientation(int32_t orientation);
|
||||
void setPointerIcon(const SpriteIcon& icon);
|
||||
void setInactivityTimeout(InactivityTimeout inactivityTimeout);
|
||||
|
||||
private:
|
||||
static const size_t MAX_RECYCLED_SPRITES = 12;
|
||||
static const size_t MAX_SPOTS = 12;
|
||||
|
||||
enum {
|
||||
MSG_ANIMATE,
|
||||
MSG_INACTIVITY_TIMEOUT,
|
||||
};
|
||||
|
||||
struct Spot {
|
||||
static const uint32_t INVALID_ID = 0xffffffff;
|
||||
|
||||
uint32_t id;
|
||||
sp<Sprite> sprite;
|
||||
float alpha;
|
||||
float scale;
|
||||
float x, y;
|
||||
|
||||
inline Spot(uint32_t id, const sp<Sprite>& sprite)
|
||||
: id(id), sprite(sprite), alpha(1.0f), scale(1.0f),
|
||||
x(0.0f), y(0.0f), lastIcon(NULL) { }
|
||||
|
||||
void updateSprite(const SpriteIcon* icon, float x, float y);
|
||||
|
||||
private:
|
||||
const SpriteIcon* lastIcon;
|
||||
};
|
||||
|
||||
mutable Mutex mLock;
|
||||
|
||||
sp<PointerControllerPolicyInterface> mPolicy;
|
||||
sp<Looper> mLooper;
|
||||
sp<SpriteController> mSpriteController;
|
||||
sp<WeakMessageHandler> mHandler;
|
||||
|
||||
PointerResources mResources;
|
||||
|
||||
struct Locked {
|
||||
bool animationPending;
|
||||
nsecs_t animationTime;
|
||||
|
||||
int32_t displayWidth;
|
||||
int32_t displayHeight;
|
||||
int32_t displayOrientation;
|
||||
|
||||
InactivityTimeout inactivityTimeout;
|
||||
|
||||
Presentation presentation;
|
||||
bool presentationChanged;
|
||||
|
||||
int32_t pointerFadeDirection;
|
||||
float pointerX;
|
||||
float pointerY;
|
||||
float pointerAlpha;
|
||||
sp<Sprite> pointerSprite;
|
||||
SpriteIcon pointerIcon;
|
||||
bool pointerIconChanged;
|
||||
|
||||
int32_t buttonState;
|
||||
|
||||
Vector<Spot*> spots;
|
||||
Vector<sp<Sprite> > recycledSprites;
|
||||
} mLocked;
|
||||
|
||||
bool getBoundsLocked(float* outMinX, float* outMinY, float* outMaxX, float* outMaxY) const;
|
||||
void setPositionLocked(float x, float y);
|
||||
|
||||
void handleMessage(const Message& message);
|
||||
void doAnimate();
|
||||
void doInactivityTimeout();
|
||||
|
||||
void startAnimationLocked();
|
||||
|
||||
void resetInactivityTimeoutLocked();
|
||||
void removeInactivityTimeoutLocked();
|
||||
void updatePointerLocked();
|
||||
|
||||
Spot* getSpotLocked(uint32_t id);
|
||||
Spot* createAndAddSpotLocked(uint32_t id);
|
||||
Spot* removeFirstFadingSpotLocked();
|
||||
void releaseSpotLocked(Spot* spot);
|
||||
void fadeOutAndReleaseSpotLocked(Spot* spot);
|
||||
void fadeOutAndReleaseAllSpotsLocked();
|
||||
|
||||
void loadResources();
|
||||
};
|
||||
|
||||
} // namespace android
|
||||
|
||||
#endif // _UI_POINTER_CONTROLLER_H
|
|
@ -0,0 +1,481 @@
|
|||
/*
|
||||
* Copyright (C) 2011 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#define LOG_TAG "Sprites"
|
||||
|
||||
//#define LOG_NDEBUG 0
|
||||
|
||||
#include "SpriteController.h"
|
||||
|
||||
#include <cutils/log.h>
|
||||
#include <utils/String8.h>
|
||||
|
||||
#include <SkBitmap.h>
|
||||
#include <SkCanvas.h>
|
||||
#include <SkColor.h>
|
||||
#include <SkPaint.h>
|
||||
#include <SkXfermode.h>
|
||||
|
||||
namespace android {
|
||||
|
||||
// --- SpriteController ---
|
||||
|
||||
SpriteController::SpriteController(const sp<Looper>& looper, int32_t overlayLayer) :
|
||||
mLooper(looper), mOverlayLayer(overlayLayer) {
|
||||
mHandler = new WeakMessageHandler(this);
|
||||
|
||||
mLocked.transactionNestingCount = 0;
|
||||
mLocked.deferredSpriteUpdate = false;
|
||||
}
|
||||
|
||||
SpriteController::~SpriteController() {
|
||||
mLooper->removeMessages(mHandler);
|
||||
|
||||
if (mSurfaceComposerClient != NULL) {
|
||||
mSurfaceComposerClient->dispose();
|
||||
mSurfaceComposerClient.clear();
|
||||
}
|
||||
}
|
||||
|
||||
sp<Sprite> SpriteController::createSprite() {
|
||||
return new SpriteImpl(this);
|
||||
}
|
||||
|
||||
void SpriteController::openTransaction() {
|
||||
AutoMutex _l(mLock);
|
||||
|
||||
mLocked.transactionNestingCount += 1;
|
||||
}
|
||||
|
||||
void SpriteController::closeTransaction() {
|
||||
AutoMutex _l(mLock);
|
||||
|
||||
LOG_ALWAYS_FATAL_IF(mLocked.transactionNestingCount == 0,
|
||||
"Sprite closeTransaction() called but there is no open sprite transaction");
|
||||
|
||||
mLocked.transactionNestingCount -= 1;
|
||||
if (mLocked.transactionNestingCount == 0 && mLocked.deferredSpriteUpdate) {
|
||||
mLocked.deferredSpriteUpdate = false;
|
||||
mLooper->sendMessage(mHandler, Message(MSG_UPDATE_SPRITES));
|
||||
}
|
||||
}
|
||||
|
||||
void SpriteController::invalidateSpriteLocked(const sp<SpriteImpl>& sprite) {
|
||||
bool wasEmpty = mLocked.invalidatedSprites.isEmpty();
|
||||
mLocked.invalidatedSprites.push(sprite);
|
||||
if (wasEmpty) {
|
||||
if (mLocked.transactionNestingCount != 0) {
|
||||
mLocked.deferredSpriteUpdate = true;
|
||||
} else {
|
||||
mLooper->sendMessage(mHandler, Message(MSG_UPDATE_SPRITES));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SpriteController::disposeSurfaceLocked(const sp<SurfaceControl>& surfaceControl) {
|
||||
bool wasEmpty = mLocked.disposedSurfaces.isEmpty();
|
||||
mLocked.disposedSurfaces.push(surfaceControl);
|
||||
if (wasEmpty) {
|
||||
mLooper->sendMessage(mHandler, Message(MSG_DISPOSE_SURFACES));
|
||||
}
|
||||
}
|
||||
|
||||
void SpriteController::handleMessage(const Message& message) {
|
||||
switch (message.what) {
|
||||
case MSG_UPDATE_SPRITES:
|
||||
doUpdateSprites();
|
||||
break;
|
||||
case MSG_DISPOSE_SURFACES:
|
||||
doDisposeSurfaces();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void SpriteController::doUpdateSprites() {
|
||||
// Collect information about sprite updates.
|
||||
// Each sprite update record includes a reference to its associated sprite so we can
|
||||
// be certain the sprites will not be deleted while this function runs. Sprites
|
||||
// may invalidate themselves again during this time but we will handle those changes
|
||||
// in the next iteration.
|
||||
Vector<SpriteUpdate> updates;
|
||||
size_t numSprites;
|
||||
{ // acquire lock
|
||||
AutoMutex _l(mLock);
|
||||
|
||||
numSprites = mLocked.invalidatedSprites.size();
|
||||
for (size_t i = 0; i < numSprites; i++) {
|
||||
const sp<SpriteImpl>& sprite = mLocked.invalidatedSprites.itemAt(i);
|
||||
|
||||
updates.push(SpriteUpdate(sprite, sprite->getStateLocked()));
|
||||
sprite->resetDirtyLocked();
|
||||
}
|
||||
mLocked.invalidatedSprites.clear();
|
||||
} // release lock
|
||||
|
||||
// Create missing surfaces.
|
||||
bool surfaceChanged = false;
|
||||
for (size_t i = 0; i < numSprites; i++) {
|
||||
SpriteUpdate& update = updates.editItemAt(i);
|
||||
|
||||
if (update.state.surfaceControl == NULL && update.state.wantSurfaceVisible()) {
|
||||
update.state.surfaceWidth = update.state.icon.bitmap.width();
|
||||
update.state.surfaceHeight = update.state.icon.bitmap.height();
|
||||
update.state.surfaceDrawn = false;
|
||||
update.state.surfaceVisible = false;
|
||||
update.state.surfaceControl = obtainSurface(
|
||||
update.state.surfaceWidth, update.state.surfaceHeight);
|
||||
if (update.state.surfaceControl != NULL) {
|
||||
update.surfaceChanged = surfaceChanged = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Resize sprites if needed, inside a global transaction.
|
||||
bool haveGlobalTransaction = false;
|
||||
for (size_t i = 0; i < numSprites; i++) {
|
||||
SpriteUpdate& update = updates.editItemAt(i);
|
||||
|
||||
if (update.state.surfaceControl != NULL && update.state.wantSurfaceVisible()) {
|
||||
int32_t desiredWidth = update.state.icon.bitmap.width();
|
||||
int32_t desiredHeight = update.state.icon.bitmap.height();
|
||||
if (update.state.surfaceWidth < desiredWidth
|
||||
|| update.state.surfaceHeight < desiredHeight) {
|
||||
if (!haveGlobalTransaction) {
|
||||
SurfaceComposerClient::openGlobalTransaction();
|
||||
haveGlobalTransaction = true;
|
||||
}
|
||||
|
||||
status_t status = update.state.surfaceControl->setSize(desiredWidth, desiredHeight);
|
||||
if (status) {
|
||||
ALOGE("Error %d resizing sprite surface from %dx%d to %dx%d",
|
||||
status, update.state.surfaceWidth, update.state.surfaceHeight,
|
||||
desiredWidth, desiredHeight);
|
||||
} else {
|
||||
update.state.surfaceWidth = desiredWidth;
|
||||
update.state.surfaceHeight = desiredHeight;
|
||||
update.state.surfaceDrawn = false;
|
||||
update.surfaceChanged = surfaceChanged = true;
|
||||
|
||||
if (update.state.surfaceVisible) {
|
||||
status = update.state.surfaceControl->hide();
|
||||
if (status) {
|
||||
ALOGE("Error %d hiding sprite surface after resize.", status);
|
||||
} else {
|
||||
update.state.surfaceVisible = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (haveGlobalTransaction) {
|
||||
SurfaceComposerClient::closeGlobalTransaction();
|
||||
}
|
||||
|
||||
// Redraw sprites if needed.
|
||||
for (size_t i = 0; i < numSprites; i++) {
|
||||
SpriteUpdate& update = updates.editItemAt(i);
|
||||
|
||||
if ((update.state.dirty & DIRTY_BITMAP) && update.state.surfaceDrawn) {
|
||||
update.state.surfaceDrawn = false;
|
||||
update.surfaceChanged = surfaceChanged = true;
|
||||
}
|
||||
|
||||
if (update.state.surfaceControl != NULL && !update.state.surfaceDrawn
|
||||
&& update.state.wantSurfaceVisible()) {
|
||||
sp<Surface> surface = update.state.surfaceControl->getSurface();
|
||||
Surface::SurfaceInfo surfaceInfo;
|
||||
status_t status = surface->lock(&surfaceInfo);
|
||||
if (status) {
|
||||
ALOGE("Error %d locking sprite surface before drawing.", status);
|
||||
} else {
|
||||
SkBitmap surfaceBitmap;
|
||||
ssize_t bpr = surfaceInfo.s * bytesPerPixel(surfaceInfo.format);
|
||||
surfaceBitmap.setConfig(SkBitmap::kARGB_8888_Config,
|
||||
surfaceInfo.w, surfaceInfo.h, bpr);
|
||||
surfaceBitmap.setPixels(surfaceInfo.bits);
|
||||
|
||||
SkCanvas surfaceCanvas;
|
||||
surfaceCanvas.setBitmapDevice(surfaceBitmap);
|
||||
|
||||
SkPaint paint;
|
||||
paint.setXfermodeMode(SkXfermode::kSrc_Mode);
|
||||
surfaceCanvas.drawBitmap(update.state.icon.bitmap, 0, 0, &paint);
|
||||
|
||||
if (surfaceInfo.w > uint32_t(update.state.icon.bitmap.width())) {
|
||||
paint.setColor(0); // transparent fill color
|
||||
surfaceCanvas.drawRectCoords(update.state.icon.bitmap.width(), 0,
|
||||
surfaceInfo.w, update.state.icon.bitmap.height(), paint);
|
||||
}
|
||||
if (surfaceInfo.h > uint32_t(update.state.icon.bitmap.height())) {
|
||||
paint.setColor(0); // transparent fill color
|
||||
surfaceCanvas.drawRectCoords(0, update.state.icon.bitmap.height(),
|
||||
surfaceInfo.w, surfaceInfo.h, paint);
|
||||
}
|
||||
|
||||
status = surface->unlockAndPost();
|
||||
if (status) {
|
||||
ALOGE("Error %d unlocking and posting sprite surface after drawing.", status);
|
||||
} else {
|
||||
update.state.surfaceDrawn = true;
|
||||
update.surfaceChanged = surfaceChanged = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Set sprite surface properties and make them visible.
|
||||
bool haveTransaction = false;
|
||||
for (size_t i = 0; i < numSprites; i++) {
|
||||
SpriteUpdate& update = updates.editItemAt(i);
|
||||
|
||||
bool wantSurfaceVisibleAndDrawn = update.state.wantSurfaceVisible()
|
||||
&& update.state.surfaceDrawn;
|
||||
bool becomingVisible = wantSurfaceVisibleAndDrawn && !update.state.surfaceVisible;
|
||||
bool becomingHidden = !wantSurfaceVisibleAndDrawn && update.state.surfaceVisible;
|
||||
if (update.state.surfaceControl != NULL && (becomingVisible || becomingHidden
|
||||
|| (wantSurfaceVisibleAndDrawn && (update.state.dirty & (DIRTY_ALPHA
|
||||
| DIRTY_POSITION | DIRTY_TRANSFORMATION_MATRIX | DIRTY_LAYER
|
||||
| DIRTY_VISIBILITY | DIRTY_HOTSPOT))))) {
|
||||
status_t status;
|
||||
if (!haveTransaction) {
|
||||
SurfaceComposerClient::openGlobalTransaction();
|
||||
haveTransaction = true;
|
||||
}
|
||||
|
||||
if (wantSurfaceVisibleAndDrawn
|
||||
&& (becomingVisible || (update.state.dirty & DIRTY_ALPHA))) {
|
||||
status = update.state.surfaceControl->setAlpha(update.state.alpha);
|
||||
if (status) {
|
||||
ALOGE("Error %d setting sprite surface alpha.", status);
|
||||
}
|
||||
}
|
||||
|
||||
if (wantSurfaceVisibleAndDrawn
|
||||
&& (becomingVisible || (update.state.dirty & (DIRTY_POSITION
|
||||
| DIRTY_HOTSPOT)))) {
|
||||
status = update.state.surfaceControl->setPosition(
|
||||
update.state.positionX - update.state.icon.hotSpotX,
|
||||
update.state.positionY - update.state.icon.hotSpotY);
|
||||
if (status) {
|
||||
ALOGE("Error %d setting sprite surface position.", status);
|
||||
}
|
||||
}
|
||||
|
||||
if (wantSurfaceVisibleAndDrawn
|
||||
&& (becomingVisible
|
||||
|| (update.state.dirty & DIRTY_TRANSFORMATION_MATRIX))) {
|
||||
status = update.state.surfaceControl->setMatrix(
|
||||
update.state.transformationMatrix.dsdx,
|
||||
update.state.transformationMatrix.dtdx,
|
||||
update.state.transformationMatrix.dsdy,
|
||||
update.state.transformationMatrix.dtdy);
|
||||
if (status) {
|
||||
ALOGE("Error %d setting sprite surface transformation matrix.", status);
|
||||
}
|
||||
}
|
||||
|
||||
int32_t surfaceLayer = mOverlayLayer + update.state.layer;
|
||||
if (wantSurfaceVisibleAndDrawn
|
||||
&& (becomingVisible || (update.state.dirty & DIRTY_LAYER))) {
|
||||
status = update.state.surfaceControl->setLayer(surfaceLayer);
|
||||
if (status) {
|
||||
ALOGE("Error %d setting sprite surface layer.", status);
|
||||
}
|
||||
}
|
||||
|
||||
if (becomingVisible) {
|
||||
status = update.state.surfaceControl->show(surfaceLayer);
|
||||
if (status) {
|
||||
ALOGE("Error %d showing sprite surface.", status);
|
||||
} else {
|
||||
update.state.surfaceVisible = true;
|
||||
update.surfaceChanged = surfaceChanged = true;
|
||||
}
|
||||
} else if (becomingHidden) {
|
||||
status = update.state.surfaceControl->hide();
|
||||
if (status) {
|
||||
ALOGE("Error %d hiding sprite surface.", status);
|
||||
} else {
|
||||
update.state.surfaceVisible = false;
|
||||
update.surfaceChanged = surfaceChanged = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (haveTransaction) {
|
||||
SurfaceComposerClient::closeGlobalTransaction();
|
||||
}
|
||||
|
||||
// If any surfaces were changed, write back the new surface properties to the sprites.
|
||||
if (surfaceChanged) { // acquire lock
|
||||
AutoMutex _l(mLock);
|
||||
|
||||
for (size_t i = 0; i < numSprites; i++) {
|
||||
const SpriteUpdate& update = updates.itemAt(i);
|
||||
|
||||
if (update.surfaceChanged) {
|
||||
update.sprite->setSurfaceLocked(update.state.surfaceControl,
|
||||
update.state.surfaceWidth, update.state.surfaceHeight,
|
||||
update.state.surfaceDrawn, update.state.surfaceVisible);
|
||||
}
|
||||
}
|
||||
} // release lock
|
||||
|
||||
// Clear the sprite update vector outside the lock. It is very important that
|
||||
// we do not clear sprite references inside the lock since we could be releasing
|
||||
// the last remaining reference to the sprite here which would result in the
|
||||
// sprite being deleted and the lock being reacquired by the sprite destructor
|
||||
// while already held.
|
||||
updates.clear();
|
||||
}
|
||||
|
||||
void SpriteController::doDisposeSurfaces() {
|
||||
// Collect disposed surfaces.
|
||||
Vector<sp<SurfaceControl> > disposedSurfaces;
|
||||
{ // acquire lock
|
||||
AutoMutex _l(mLock);
|
||||
|
||||
disposedSurfaces = mLocked.disposedSurfaces;
|
||||
mLocked.disposedSurfaces.clear();
|
||||
} // release lock
|
||||
|
||||
// Release the last reference to each surface outside of the lock.
|
||||
// We don't want the surfaces to be deleted while we are holding our lock.
|
||||
disposedSurfaces.clear();
|
||||
}
|
||||
|
||||
void SpriteController::ensureSurfaceComposerClient() {
|
||||
if (mSurfaceComposerClient == NULL) {
|
||||
mSurfaceComposerClient = new SurfaceComposerClient();
|
||||
}
|
||||
}
|
||||
|
||||
sp<SurfaceControl> SpriteController::obtainSurface(int32_t width, int32_t height) {
|
||||
ensureSurfaceComposerClient();
|
||||
|
||||
sp<SurfaceControl> surfaceControl = mSurfaceComposerClient->createSurface(
|
||||
String8("Sprite"), 0, width, height, PIXEL_FORMAT_RGBA_8888);
|
||||
if (surfaceControl == NULL || !surfaceControl->isValid()
|
||||
|| !surfaceControl->getSurface()->isValid()) {
|
||||
ALOGE("Error creating sprite surface.");
|
||||
return NULL;
|
||||
}
|
||||
return surfaceControl;
|
||||
}
|
||||
|
||||
|
||||
// --- SpriteController::SpriteImpl ---
|
||||
|
||||
SpriteController::SpriteImpl::SpriteImpl(const sp<SpriteController> controller) :
|
||||
mController(controller) {
|
||||
}
|
||||
|
||||
SpriteController::SpriteImpl::~SpriteImpl() {
|
||||
AutoMutex _m(mController->mLock);
|
||||
|
||||
// Let the controller take care of deleting the last reference to sprite
|
||||
// surfaces so that we do not block the caller on an IPC here.
|
||||
if (mLocked.state.surfaceControl != NULL) {
|
||||
mController->disposeSurfaceLocked(mLocked.state.surfaceControl);
|
||||
mLocked.state.surfaceControl.clear();
|
||||
}
|
||||
}
|
||||
|
||||
void SpriteController::SpriteImpl::setIcon(const SpriteIcon& icon) {
|
||||
AutoMutex _l(mController->mLock);
|
||||
|
||||
uint32_t dirty;
|
||||
if (icon.isValid()) {
|
||||
icon.bitmap.copyTo(&mLocked.state.icon.bitmap, SkBitmap::kARGB_8888_Config);
|
||||
|
||||
if (!mLocked.state.icon.isValid()
|
||||
|| mLocked.state.icon.hotSpotX != icon.hotSpotX
|
||||
|| mLocked.state.icon.hotSpotY != icon.hotSpotY) {
|
||||
mLocked.state.icon.hotSpotX = icon.hotSpotX;
|
||||
mLocked.state.icon.hotSpotY = icon.hotSpotY;
|
||||
dirty = DIRTY_BITMAP | DIRTY_HOTSPOT;
|
||||
} else {
|
||||
dirty = DIRTY_BITMAP;
|
||||
}
|
||||
} else if (mLocked.state.icon.isValid()) {
|
||||
mLocked.state.icon.bitmap.reset();
|
||||
dirty = DIRTY_BITMAP | DIRTY_HOTSPOT;
|
||||
} else {
|
||||
return; // setting to invalid icon and already invalid so nothing to do
|
||||
}
|
||||
|
||||
invalidateLocked(dirty);
|
||||
}
|
||||
|
||||
void SpriteController::SpriteImpl::setVisible(bool visible) {
|
||||
AutoMutex _l(mController->mLock);
|
||||
|
||||
if (mLocked.state.visible != visible) {
|
||||
mLocked.state.visible = visible;
|
||||
invalidateLocked(DIRTY_VISIBILITY);
|
||||
}
|
||||
}
|
||||
|
||||
void SpriteController::SpriteImpl::setPosition(float x, float y) {
|
||||
AutoMutex _l(mController->mLock);
|
||||
|
||||
if (mLocked.state.positionX != x || mLocked.state.positionY != y) {
|
||||
mLocked.state.positionX = x;
|
||||
mLocked.state.positionY = y;
|
||||
invalidateLocked(DIRTY_POSITION);
|
||||
}
|
||||
}
|
||||
|
||||
void SpriteController::SpriteImpl::setLayer(int32_t layer) {
|
||||
AutoMutex _l(mController->mLock);
|
||||
|
||||
if (mLocked.state.layer != layer) {
|
||||
mLocked.state.layer = layer;
|
||||
invalidateLocked(DIRTY_LAYER);
|
||||
}
|
||||
}
|
||||
|
||||
void SpriteController::SpriteImpl::setAlpha(float alpha) {
|
||||
AutoMutex _l(mController->mLock);
|
||||
|
||||
if (mLocked.state.alpha != alpha) {
|
||||
mLocked.state.alpha = alpha;
|
||||
invalidateLocked(DIRTY_ALPHA);
|
||||
}
|
||||
}
|
||||
|
||||
void SpriteController::SpriteImpl::setTransformationMatrix(
|
||||
const SpriteTransformationMatrix& matrix) {
|
||||
AutoMutex _l(mController->mLock);
|
||||
|
||||
if (mLocked.state.transformationMatrix != matrix) {
|
||||
mLocked.state.transformationMatrix = matrix;
|
||||
invalidateLocked(DIRTY_TRANSFORMATION_MATRIX);
|
||||
}
|
||||
}
|
||||
|
||||
void SpriteController::SpriteImpl::invalidateLocked(uint32_t dirty) {
|
||||
bool wasDirty = mLocked.state.dirty;
|
||||
mLocked.state.dirty |= dirty;
|
||||
|
||||
if (!wasDirty) {
|
||||
mController->invalidateSpriteLocked(this);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace android
|
|
@ -0,0 +1,295 @@
|
|||
/*
|
||||
* Copyright (C) 2011 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef _UI_SPRITES_H
|
||||
#define _UI_SPRITES_H
|
||||
|
||||
#include <utils/RefBase.h>
|
||||
#include <utils/Looper.h>
|
||||
|
||||
#include <surfaceflinger/Surface.h>
|
||||
#include <surfaceflinger/SurfaceComposerClient.h>
|
||||
#include <surfaceflinger/ISurfaceComposer.h>
|
||||
|
||||
#include <SkBitmap.h>
|
||||
|
||||
namespace android {
|
||||
|
||||
/*
|
||||
* Transformation matrix for a sprite.
|
||||
*/
|
||||
struct SpriteTransformationMatrix {
|
||||
inline SpriteTransformationMatrix() : dsdx(1.0f), dtdx(0.0f), dsdy(0.0f), dtdy(1.0f) { }
|
||||
inline SpriteTransformationMatrix(float dsdx, float dtdx, float dsdy, float dtdy) :
|
||||
dsdx(dsdx), dtdx(dtdx), dsdy(dsdy), dtdy(dtdy) { }
|
||||
|
||||
float dsdx;
|
||||
float dtdx;
|
||||
float dsdy;
|
||||
float dtdy;
|
||||
|
||||
inline bool operator== (const SpriteTransformationMatrix& other) {
|
||||
return dsdx == other.dsdx
|
||||
&& dtdx == other.dtdx
|
||||
&& dsdy == other.dsdy
|
||||
&& dtdy == other.dtdy;
|
||||
}
|
||||
|
||||
inline bool operator!= (const SpriteTransformationMatrix& other) {
|
||||
return !(*this == other);
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
* Icon that a sprite displays, including its hotspot.
|
||||
*/
|
||||
struct SpriteIcon {
|
||||
inline SpriteIcon() : hotSpotX(0), hotSpotY(0) { }
|
||||
inline SpriteIcon(const SkBitmap& bitmap, float hotSpotX, float hotSpotY) :
|
||||
bitmap(bitmap), hotSpotX(hotSpotX), hotSpotY(hotSpotY) { }
|
||||
|
||||
SkBitmap bitmap;
|
||||
float hotSpotX;
|
||||
float hotSpotY;
|
||||
|
||||
inline SpriteIcon copy() const {
|
||||
SkBitmap bitmapCopy;
|
||||
bitmap.copyTo(&bitmapCopy, SkBitmap::kARGB_8888_Config);
|
||||
return SpriteIcon(bitmapCopy, hotSpotX, hotSpotY);
|
||||
}
|
||||
|
||||
inline void reset() {
|
||||
bitmap.reset();
|
||||
hotSpotX = 0;
|
||||
hotSpotY = 0;
|
||||
}
|
||||
|
||||
inline bool isValid() const {
|
||||
return !bitmap.isNull() && !bitmap.empty();
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
* A sprite is a simple graphical object that is displayed on-screen above other layers.
|
||||
* The basic sprite class is an interface.
|
||||
* The implementation is provided by the sprite controller.
|
||||
*/
|
||||
class Sprite : public RefBase {
|
||||
protected:
|
||||
Sprite() { }
|
||||
virtual ~Sprite() { }
|
||||
|
||||
public:
|
||||
enum {
|
||||
// The base layer for pointer sprites.
|
||||
BASE_LAYER_POINTER = 0, // reserve space for 1 pointer
|
||||
|
||||
// The base layer for spot sprites.
|
||||
BASE_LAYER_SPOT = 1, // reserve space for MAX_POINTER_ID spots
|
||||
};
|
||||
|
||||
/* Sets the bitmap that is drawn by the sprite.
|
||||
* The sprite retains a copy of the bitmap for subsequent rendering. */
|
||||
virtual void setIcon(const SpriteIcon& icon) = 0;
|
||||
|
||||
inline void clearIcon() {
|
||||
setIcon(SpriteIcon());
|
||||
}
|
||||
|
||||
/* Sets whether the sprite is visible. */
|
||||
virtual void setVisible(bool visible) = 0;
|
||||
|
||||
/* Sets the sprite position on screen, relative to the sprite's hot spot. */
|
||||
virtual void setPosition(float x, float y) = 0;
|
||||
|
||||
/* Sets the layer of the sprite, relative to the system sprite overlay layer.
|
||||
* Layer 0 is the overlay layer, > 0 appear above this layer. */
|
||||
virtual void setLayer(int32_t layer) = 0;
|
||||
|
||||
/* Sets the sprite alpha blend ratio between 0.0 and 1.0. */
|
||||
virtual void setAlpha(float alpha) = 0;
|
||||
|
||||
/* Sets the sprite transformation matrix. */
|
||||
virtual void setTransformationMatrix(const SpriteTransformationMatrix& matrix) = 0;
|
||||
};
|
||||
|
||||
/*
|
||||
* Displays sprites on the screen.
|
||||
*
|
||||
* This interface is used by PointerController and SpotController to draw pointers or
|
||||
* spot representations of fingers. It is not intended for general purpose use
|
||||
* by other components.
|
||||
*
|
||||
* All sprite position updates and rendering is performed asynchronously.
|
||||
*
|
||||
* Clients are responsible for animating sprites by periodically updating their properties.
|
||||
*/
|
||||
class SpriteController : public MessageHandler {
|
||||
protected:
|
||||
virtual ~SpriteController();
|
||||
|
||||
public:
|
||||
SpriteController(const sp<Looper>& looper, int32_t overlayLayer);
|
||||
|
||||
/* Creates a new sprite, initially invisible. */
|
||||
sp<Sprite> createSprite();
|
||||
|
||||
/* Opens or closes a transaction to perform a batch of sprite updates as part of
|
||||
* a single operation such as setPosition and setAlpha. It is not necessary to
|
||||
* open a transaction when updating a single property.
|
||||
* Calls to openTransaction() nest and must be matched by an equal number
|
||||
* of calls to closeTransaction(). */
|
||||
void openTransaction();
|
||||
void closeTransaction();
|
||||
|
||||
private:
|
||||
enum {
|
||||
MSG_UPDATE_SPRITES,
|
||||
MSG_DISPOSE_SURFACES,
|
||||
};
|
||||
|
||||
enum {
|
||||
DIRTY_BITMAP = 1 << 0,
|
||||
DIRTY_ALPHA = 1 << 1,
|
||||
DIRTY_POSITION = 1 << 2,
|
||||
DIRTY_TRANSFORMATION_MATRIX = 1 << 3,
|
||||
DIRTY_LAYER = 1 << 4,
|
||||
DIRTY_VISIBILITY = 1 << 5,
|
||||
DIRTY_HOTSPOT = 1 << 6,
|
||||
};
|
||||
|
||||
/* Describes the state of a sprite.
|
||||
* This structure is designed so that it can be copied during updates so that
|
||||
* surfaces can be resized and redrawn without blocking the client by holding a lock
|
||||
* on the sprites for a long time.
|
||||
* Note that the SkBitmap holds a reference to a shared (and immutable) pixel ref. */
|
||||
struct SpriteState {
|
||||
inline SpriteState() :
|
||||
dirty(0), visible(false),
|
||||
positionX(0), positionY(0), layer(0), alpha(1.0f),
|
||||
surfaceWidth(0), surfaceHeight(0), surfaceDrawn(false), surfaceVisible(false) {
|
||||
}
|
||||
|
||||
uint32_t dirty;
|
||||
|
||||
SpriteIcon icon;
|
||||
bool visible;
|
||||
float positionX;
|
||||
float positionY;
|
||||
int32_t layer;
|
||||
float alpha;
|
||||
SpriteTransformationMatrix transformationMatrix;
|
||||
|
||||
sp<SurfaceControl> surfaceControl;
|
||||
int32_t surfaceWidth;
|
||||
int32_t surfaceHeight;
|
||||
bool surfaceDrawn;
|
||||
bool surfaceVisible;
|
||||
|
||||
inline bool wantSurfaceVisible() const {
|
||||
return visible && alpha > 0.0f && icon.isValid();
|
||||
}
|
||||
};
|
||||
|
||||
/* Client interface for a sprite.
|
||||
* Requests acquire a lock on the controller, update local state and request the
|
||||
* controller to invalidate the sprite.
|
||||
* The real heavy lifting of creating, resizing and redrawing surfaces happens
|
||||
* asynchronously with no locks held except in short critical section to copy
|
||||
* the sprite state before the work and update the sprite surface control afterwards.
|
||||
*/
|
||||
class SpriteImpl : public Sprite {
|
||||
protected:
|
||||
virtual ~SpriteImpl();
|
||||
|
||||
public:
|
||||
SpriteImpl(const sp<SpriteController> controller);
|
||||
|
||||
virtual void setIcon(const SpriteIcon& icon);
|
||||
virtual void setVisible(bool visible);
|
||||
virtual void setPosition(float x, float y);
|
||||
virtual void setLayer(int32_t layer);
|
||||
virtual void setAlpha(float alpha);
|
||||
virtual void setTransformationMatrix(const SpriteTransformationMatrix& matrix);
|
||||
|
||||
inline const SpriteState& getStateLocked() const {
|
||||
return mLocked.state;
|
||||
}
|
||||
|
||||
inline void resetDirtyLocked() {
|
||||
mLocked.state.dirty = 0;
|
||||
}
|
||||
|
||||
inline void setSurfaceLocked(const sp<SurfaceControl>& surfaceControl,
|
||||
int32_t width, int32_t height, bool drawn, bool visible) {
|
||||
mLocked.state.surfaceControl = surfaceControl;
|
||||
mLocked.state.surfaceWidth = width;
|
||||
mLocked.state.surfaceHeight = height;
|
||||
mLocked.state.surfaceDrawn = drawn;
|
||||
mLocked.state.surfaceVisible = visible;
|
||||
}
|
||||
|
||||
private:
|
||||
sp<SpriteController> mController;
|
||||
|
||||
struct Locked {
|
||||
SpriteState state;
|
||||
} mLocked; // guarded by mController->mLock
|
||||
|
||||
void invalidateLocked(uint32_t dirty);
|
||||
};
|
||||
|
||||
/* Stores temporary information collected during the sprite update cycle. */
|
||||
struct SpriteUpdate {
|
||||
inline SpriteUpdate() : surfaceChanged(false) { }
|
||||
inline SpriteUpdate(const sp<SpriteImpl> sprite, const SpriteState& state) :
|
||||
sprite(sprite), state(state), surfaceChanged(false) {
|
||||
}
|
||||
|
||||
sp<SpriteImpl> sprite;
|
||||
SpriteState state;
|
||||
bool surfaceChanged;
|
||||
};
|
||||
|
||||
mutable Mutex mLock;
|
||||
|
||||
sp<Looper> mLooper;
|
||||
const int32_t mOverlayLayer;
|
||||
sp<WeakMessageHandler> mHandler;
|
||||
|
||||
sp<SurfaceComposerClient> mSurfaceComposerClient;
|
||||
|
||||
struct Locked {
|
||||
Vector<sp<SpriteImpl> > invalidatedSprites;
|
||||
Vector<sp<SurfaceControl> > disposedSurfaces;
|
||||
uint32_t transactionNestingCount;
|
||||
bool deferredSpriteUpdate;
|
||||
} mLocked; // guarded by mLock
|
||||
|
||||
void invalidateSpriteLocked(const sp<SpriteImpl>& sprite);
|
||||
void disposeSurfaceLocked(const sp<SurfaceControl>& surfaceControl);
|
||||
|
||||
void handleMessage(const Message& message);
|
||||
void doUpdateSprites();
|
||||
void doDisposeSurfaces();
|
||||
|
||||
void ensureSurfaceComposerClient();
|
||||
sp<SurfaceControl> obtainSurface(int32_t width, int32_t height);
|
||||
};
|
||||
|
||||
} // namespace android
|
||||
|
||||
#endif // _UI_SPRITES_H
|
|
@ -0,0 +1,171 @@
|
|||
/*
|
||||
* Copyright (C) 2010 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#define LOG_TAG "VirtualKeyMap"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "VirtualKeyMap.h"
|
||||
#include <utils/Log.h>
|
||||
#include <utils/Errors.h>
|
||||
#include <utils/Tokenizer.h>
|
||||
#include <utils/Timers.h>
|
||||
|
||||
// Enables debug output for the parser.
|
||||
#define DEBUG_PARSER 0
|
||||
|
||||
// Enables debug output for parser performance.
|
||||
#define DEBUG_PARSER_PERFORMANCE 0
|
||||
|
||||
|
||||
namespace android {
|
||||
|
||||
static const char* WHITESPACE = " \t\r";
|
||||
static const char* WHITESPACE_OR_FIELD_DELIMITER = " \t\r:";
|
||||
|
||||
|
||||
// --- VirtualKeyMap ---
|
||||
|
||||
VirtualKeyMap::VirtualKeyMap() {
|
||||
}
|
||||
|
||||
VirtualKeyMap::~VirtualKeyMap() {
|
||||
}
|
||||
|
||||
status_t VirtualKeyMap::load(const String8& filename, VirtualKeyMap** outMap) {
|
||||
*outMap = NULL;
|
||||
|
||||
Tokenizer* tokenizer;
|
||||
status_t status = Tokenizer::open(filename, &tokenizer);
|
||||
if (status) {
|
||||
ALOGE("Error %d opening virtual key map file %s.", status, filename.string());
|
||||
} else {
|
||||
VirtualKeyMap* map = new VirtualKeyMap();
|
||||
if (!map) {
|
||||
ALOGE("Error allocating virtual key map.");
|
||||
status = NO_MEMORY;
|
||||
} else {
|
||||
#if DEBUG_PARSER_PERFORMANCE
|
||||
nsecs_t startTime = systemTime(SYSTEM_TIME_MONOTONIC);
|
||||
#endif
|
||||
Parser parser(map, tokenizer);
|
||||
status = parser.parse();
|
||||
#if DEBUG_PARSER_PERFORMANCE
|
||||
nsecs_t elapsedTime = systemTime(SYSTEM_TIME_MONOTONIC) - startTime;
|
||||
ALOGD("Parsed key character map file '%s' %d lines in %0.3fms.",
|
||||
tokenizer->getFilename().string(), tokenizer->getLineNumber(),
|
||||
elapsedTime / 1000000.0);
|
||||
#endif
|
||||
if (status) {
|
||||
delete map;
|
||||
} else {
|
||||
*outMap = map;
|
||||
}
|
||||
}
|
||||
delete tokenizer;
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
// --- VirtualKeyMap::Parser ---
|
||||
|
||||
VirtualKeyMap::Parser::Parser(VirtualKeyMap* map, Tokenizer* tokenizer) :
|
||||
mMap(map), mTokenizer(tokenizer) {
|
||||
}
|
||||
|
||||
VirtualKeyMap::Parser::~Parser() {
|
||||
}
|
||||
|
||||
status_t VirtualKeyMap::Parser::parse() {
|
||||
while (!mTokenizer->isEof()) {
|
||||
#if DEBUG_PARSER
|
||||
ALOGD("Parsing %s: '%s'.", mTokenizer->getLocation().string(),
|
||||
mTokenizer->peekRemainderOfLine().string());
|
||||
#endif
|
||||
|
||||
mTokenizer->skipDelimiters(WHITESPACE);
|
||||
|
||||
if (!mTokenizer->isEol() && mTokenizer->peekChar() != '#') {
|
||||
// Multiple keys can appear on one line or they can be broken up across multiple lines.
|
||||
do {
|
||||
String8 token = mTokenizer->nextToken(WHITESPACE_OR_FIELD_DELIMITER);
|
||||
if (token != "0x01") {
|
||||
ALOGE("%s: Unknown virtual key type, expected 0x01.",
|
||||
mTokenizer->getLocation().string());
|
||||
return BAD_VALUE;
|
||||
}
|
||||
|
||||
VirtualKeyDefinition defn;
|
||||
bool success = parseNextIntField(&defn.scanCode)
|
||||
&& parseNextIntField(&defn.centerX)
|
||||
&& parseNextIntField(&defn.centerY)
|
||||
&& parseNextIntField(&defn.width)
|
||||
&& parseNextIntField(&defn.height);
|
||||
if (!success) {
|
||||
ALOGE("%s: Expected 5 colon-delimited integers in virtual key definition.",
|
||||
mTokenizer->getLocation().string());
|
||||
return BAD_VALUE;
|
||||
}
|
||||
|
||||
#if DEBUG_PARSER
|
||||
ALOGD("Parsed virtual key: scanCode=%d, centerX=%d, centerY=%d, "
|
||||
"width=%d, height=%d",
|
||||
defn.scanCode, defn.centerX, defn.centerY, defn.width, defn.height);
|
||||
#endif
|
||||
mMap->mVirtualKeys.push(defn);
|
||||
} while (consumeFieldDelimiterAndSkipWhitespace());
|
||||
|
||||
if (!mTokenizer->isEol()) {
|
||||
ALOGE("%s: Expected end of line, got '%s'.",
|
||||
mTokenizer->getLocation().string(),
|
||||
mTokenizer->peekRemainderOfLine().string());
|
||||
return BAD_VALUE;
|
||||
}
|
||||
}
|
||||
|
||||
mTokenizer->nextLine();
|
||||
}
|
||||
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
bool VirtualKeyMap::Parser::consumeFieldDelimiterAndSkipWhitespace() {
|
||||
mTokenizer->skipDelimiters(WHITESPACE);
|
||||
if (mTokenizer->peekChar() == ':') {
|
||||
mTokenizer->nextChar();
|
||||
mTokenizer->skipDelimiters(WHITESPACE);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool VirtualKeyMap::Parser::parseNextIntField(int32_t* outValue) {
|
||||
if (!consumeFieldDelimiterAndSkipWhitespace()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
String8 token = mTokenizer->nextToken(WHITESPACE_OR_FIELD_DELIMITER);
|
||||
char* end;
|
||||
*outValue = strtol(token.string(), &end, 0);
|
||||
if (token.isEmpty() || *end != '\0') {
|
||||
ALOGE("Expected an integer, got '%s'.", token.string());
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace android
|
|
@ -0,0 +1,79 @@
|
|||
/*
|
||||
* Copyright (C) 2010 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef _UI_VIRTUAL_KEY_MAP_H
|
||||
#define _UI_VIRTUAL_KEY_MAP_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "Input.h"
|
||||
#include <utils/Errors.h>
|
||||
#include <utils/KeyedVector.h>
|
||||
#include <utils/Tokenizer.h>
|
||||
#include <utils/String8.h>
|
||||
#include <utils/Unicode.h>
|
||||
|
||||
namespace android {
|
||||
|
||||
/* Describes a virtual key. */
|
||||
struct VirtualKeyDefinition {
|
||||
int32_t scanCode;
|
||||
|
||||
// configured position data, specified in display coords
|
||||
int32_t centerX;
|
||||
int32_t centerY;
|
||||
int32_t width;
|
||||
int32_t height;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Describes a collection of virtual keys on a touch screen in terms of
|
||||
* virtual scan codes and hit rectangles.
|
||||
*/
|
||||
class VirtualKeyMap {
|
||||
public:
|
||||
~VirtualKeyMap();
|
||||
|
||||
static status_t load(const String8& filename, VirtualKeyMap** outMap);
|
||||
|
||||
inline const Vector<VirtualKeyDefinition>& getVirtualKeys() const {
|
||||
return mVirtualKeys;
|
||||
}
|
||||
|
||||
private:
|
||||
class Parser {
|
||||
VirtualKeyMap* mMap;
|
||||
Tokenizer* mTokenizer;
|
||||
|
||||
public:
|
||||
Parser(VirtualKeyMap* map, Tokenizer* tokenizer);
|
||||
~Parser();
|
||||
status_t parse();
|
||||
|
||||
private:
|
||||
bool consumeFieldDelimiterAndSkipWhitespace();
|
||||
bool parseNextIntField(int32_t* outValue);
|
||||
};
|
||||
|
||||
Vector<VirtualKeyDefinition> mVirtualKeys;
|
||||
|
||||
VirtualKeyMap();
|
||||
};
|
||||
|
||||
} // namespace android
|
||||
|
||||
#endif // _UI_KEY_CHARACTER_MAP_H
|
|
@ -66,9 +66,9 @@
|
|||
#include "nsWindow.h"
|
||||
|
||||
#include "android/log.h"
|
||||
#include "ui/EventHub.h"
|
||||
#include "ui/InputReader.h"
|
||||
#include "ui/InputDispatcher.h"
|
||||
#include "libui/EventHub.h"
|
||||
#include "libui/InputReader.h"
|
||||
#include "libui/InputDispatcher.h"
|
||||
|
||||
#define LOG(args...) \
|
||||
__android_log_print(ANDROID_LOG_INFO, "Gonk" , ## args)
|
||||
|
@ -165,10 +165,12 @@ addDOMTouch(UserInputData& data, nsTouchEvent& event, int i)
|
|||
const Touch& touch = data.motion.touches[i];
|
||||
event.touches.AppendElement(
|
||||
new nsDOMTouch(touch.id,
|
||||
nsIntPoint(touch.coords.x, touch.coords.y),
|
||||
nsIntPoint(touch.coords.size, touch.coords.size),
|
||||
nsIntPoint(touch.coords.getX(), touch.coords.getY()),
|
||||
nsIntPoint(touch.coords.getAxisValue(AMOTION_EVENT_AXIS_SIZE),
|
||||
touch.coords.getAxisValue(AMOTION_EVENT_AXIS_SIZE)),
|
||||
0,
|
||||
touch.coords.pressure));
|
||||
touch.coords.getAxisValue(AMOTION_EVENT_AXIS_PRESSURE))
|
||||
);
|
||||
}
|
||||
|
||||
static nsEventStatus
|
||||
|
@ -272,19 +274,13 @@ maybeSendKeyEvent(int keyCode, bool pressed, uint64_t timeMs)
|
|||
}
|
||||
|
||||
class GeckoInputReaderPolicy : public InputReaderPolicyInterface {
|
||||
InputReaderConfiguration mConfig;
|
||||
public:
|
||||
GeckoInputReaderPolicy() {}
|
||||
|
||||
virtual bool getDisplayInfo(int32_t displayId,
|
||||
int32_t* width, int32_t* height, int32_t* orientation);
|
||||
virtual bool filterTouchEvents();
|
||||
virtual bool filterJumpyTouchEvents();
|
||||
virtual nsecs_t getVirtualKeyQuietTime();
|
||||
virtual void getVirtualKeyDefinitions(const String8& deviceName,
|
||||
Vector<VirtualKeyDefinition>& outVirtualKeyDefinitions);
|
||||
virtual void getInputDeviceCalibration(const String8& deviceName,
|
||||
InputDeviceCalibration& outCalibration);
|
||||
virtual void getExcludedDeviceNames(Vector<String8>& outExcludedDeviceNames);
|
||||
virtual void getReaderConfiguration(InputReaderConfiguration* outConfig);
|
||||
|
||||
void setDisplayInfo();
|
||||
|
||||
protected:
|
||||
virtual ~GeckoInputReaderPolicy() {}
|
||||
|
@ -298,30 +294,36 @@ public:
|
|||
|
||||
virtual void dump(String8& dump);
|
||||
|
||||
virtual void monitor() {}
|
||||
|
||||
// Called on the main thread
|
||||
virtual void dispatchOnce();
|
||||
|
||||
// notify* methods are called on the InputReaderThread
|
||||
virtual void notifyConfigurationChanged(nsecs_t eventTime);
|
||||
virtual void notifyKey(nsecs_t eventTime, int32_t deviceId, int32_t source,
|
||||
uint32_t policyFlags, int32_t action, int32_t flags, int32_t keyCode,
|
||||
int32_t scanCode, int32_t metaState, nsecs_t downTime);
|
||||
virtual void notifyMotion(nsecs_t eventTime, int32_t deviceId, int32_t source,
|
||||
uint32_t policyFlags, int32_t action, int32_t flags,
|
||||
int32_t metaState, int32_t edgeFlags,
|
||||
uint32_t pointerCount, const int32_t* pointerIds, const PointerCoords* pointerCoords,
|
||||
float xPrecision, float yPrecision, nsecs_t downTime);
|
||||
virtual void notifySwitch(nsecs_t when,
|
||||
int32_t switchCode, int32_t switchValue, uint32_t policyFlags);
|
||||
virtual void notifyConfigurationChanged(const NotifyConfigurationChangedArgs* args);
|
||||
virtual void notifyKey(const NotifyKeyArgs* args);
|
||||
virtual void notifyMotion(const NotifyMotionArgs* args);
|
||||
virtual void notifySwitch(const NotifySwitchArgs* args);
|
||||
virtual void notifyDeviceReset(const NotifyDeviceResetArgs* args);
|
||||
|
||||
virtual int32_t injectInputEvent(const InputEvent* event,
|
||||
int32_t injectorPid, int32_t injectorUid, int32_t syncMode, int32_t timeoutMillis);
|
||||
virtual void setInputWindows(const Vector<InputWindow>& inputWindows);
|
||||
virtual void setFocusedApplication(const InputApplication* inputApplication);
|
||||
int32_t injectorPid, int32_t injectorUid, int32_t syncMode, int32_t timeoutMillis,
|
||||
uint32_t policyFlags);
|
||||
|
||||
virtual void setInputWindows(const Vector<sp<InputWindowHandle> >& inputWindowHandles);
|
||||
virtual void setFocusedApplication(const sp<InputApplicationHandle>& inputApplicationHandle);
|
||||
|
||||
virtual void setInputDispatchMode(bool enabled, bool frozen);
|
||||
virtual status_t registerInputChannel(const sp<InputChannel>& inputChannel, bool monitor);
|
||||
virtual void setInputFilterEnabled(bool enabled) {}
|
||||
virtual bool transferTouchFocus(const sp<InputChannel>& fromChannel,
|
||||
const sp<InputChannel>& toChannel) { return true; }
|
||||
|
||||
virtual status_t registerInputChannel(const sp<InputChannel>& inputChannel,
|
||||
const sp<InputWindowHandle>& inputWindowHandle, bool monitor);
|
||||
virtual status_t unregisterInputChannel(const sp<InputChannel>& inputChannel);
|
||||
|
||||
|
||||
|
||||
protected:
|
||||
virtual ~GeckoInputDispatcher() {}
|
||||
|
||||
|
@ -334,138 +336,30 @@ private:
|
|||
};
|
||||
|
||||
// GeckoInputReaderPolicy
|
||||
bool
|
||||
GeckoInputReaderPolicy::getDisplayInfo(int32_t displayId,
|
||||
int32_t* width,
|
||||
int32_t* height,
|
||||
int32_t* orientation)
|
||||
void
|
||||
GeckoInputReaderPolicy::setDisplayInfo()
|
||||
{
|
||||
MOZ_STATIC_ASSERT(nsIScreen::ROTATION_0_DEG ==
|
||||
InputReaderPolicyInterface::ROTATION_0,
|
||||
DISPLAY_ORIENTATION_0,
|
||||
"Orientation enums not matched!");
|
||||
MOZ_STATIC_ASSERT(nsIScreen::ROTATION_90_DEG ==
|
||||
InputReaderPolicyInterface::ROTATION_90,
|
||||
DISPLAY_ORIENTATION_90,
|
||||
"Orientation enums not matched!");
|
||||
MOZ_STATIC_ASSERT(nsIScreen::ROTATION_180_DEG ==
|
||||
InputReaderPolicyInterface::ROTATION_180,
|
||||
DISPLAY_ORIENTATION_180,
|
||||
"Orientation enums not matched!");
|
||||
MOZ_STATIC_ASSERT(nsIScreen::ROTATION_270_DEG ==
|
||||
InputReaderPolicyInterface::ROTATION_270,
|
||||
DISPLAY_ORIENTATION_270,
|
||||
"Orientation enums not matched!");
|
||||
|
||||
// 0 is the default displayId. We only support one display
|
||||
if (displayId)
|
||||
return false;
|
||||
|
||||
if (width)
|
||||
*width = gScreenBounds.width;
|
||||
if (height)
|
||||
*height = gScreenBounds.height;
|
||||
if (orientation)
|
||||
*orientation = nsScreenGonk::GetRotation();
|
||||
return true;
|
||||
mConfig.setDisplayInfo(0, false, gScreenBounds.width, gScreenBounds.height, nsScreenGonk::GetRotation());
|
||||
}
|
||||
|
||||
bool
|
||||
GeckoInputReaderPolicy::filterTouchEvents()
|
||||
void GeckoInputReaderPolicy::getReaderConfiguration(InputReaderConfiguration* outConfig)
|
||||
{
|
||||
return false;
|
||||
*outConfig = mConfig;
|
||||
}
|
||||
|
||||
bool
|
||||
GeckoInputReaderPolicy::filterJumpyTouchEvents()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
nsecs_t
|
||||
GeckoInputReaderPolicy::getVirtualKeyQuietTime()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
GeckoInputReaderPolicy::getVirtualKeyDefinitions(const String8& deviceName,
|
||||
Vector<VirtualKeyDefinition>& outVirtualKeyDefinitions)
|
||||
{
|
||||
outVirtualKeyDefinitions.clear();
|
||||
|
||||
char vbuttonsPath[PATH_MAX];
|
||||
snprintf(vbuttonsPath, sizeof(vbuttonsPath),
|
||||
"/sys/board_properties/virtualkeys.%s",
|
||||
deviceName.string());
|
||||
ScopedClose fd(open(vbuttonsPath, O_RDONLY));
|
||||
if (0 > fd.mFd) {
|
||||
LOG("No vbuttons for mt device %s", deviceName.string());
|
||||
return;
|
||||
}
|
||||
|
||||
// This device has vbuttons. Process the configuration.
|
||||
char config[1024];
|
||||
ssize_t nread;
|
||||
do {
|
||||
nread = read(fd.mFd, config, sizeof(config));
|
||||
} while (-1 == nread && EINTR == errno);
|
||||
|
||||
if (0 > nread) {
|
||||
LOG("Error reading virtualkey configuration");
|
||||
return;
|
||||
}
|
||||
|
||||
config[nread] = '\0';
|
||||
|
||||
LOG("Device %s has vbutton config '%s'", deviceName.string(), config);
|
||||
|
||||
char* first = config;
|
||||
char* magic;
|
||||
char* state;
|
||||
while ((magic = strtok_r(first, ":", &state))) {
|
||||
// XXX not clear what "0x01" is ... maybe a version
|
||||
// number? See InputManager.java.
|
||||
if (strcmp(magic, "0x01")) {
|
||||
LOG(" magic 0x01 tag missing");
|
||||
break;
|
||||
}
|
||||
first = NULL;
|
||||
|
||||
const char *scanCode, *centerX, *centerY, *width, *height;
|
||||
if (!((scanCode = strtok_r(NULL, ":", &state)) &&
|
||||
(centerX = strtok_r(NULL, ":", &state)) &&
|
||||
(centerY = strtok_r(NULL, ":", &state)) &&
|
||||
(width = strtok_r(NULL, ":", &state)) &&
|
||||
(height = strtok_r(NULL, ":", &state)))) {
|
||||
LOG(" failed to read bound params");
|
||||
break;
|
||||
}
|
||||
|
||||
// NB: these coordinates are in *screen* space, not input
|
||||
// space. That means the values in /sys/board_config make
|
||||
// assumptions about how the raw input events are mapped
|
||||
// ... le sigh.
|
||||
VirtualKeyDefinition def;
|
||||
def.scanCode = atoi(scanCode);
|
||||
def.centerX = atoi(centerX);
|
||||
def.centerY = atoi(centerY);
|
||||
def.width = atoi(width);
|
||||
def.height = atoi(height);
|
||||
outVirtualKeyDefinitions.push(def);
|
||||
|
||||
LOG(" configured vbutton code=%d at <x=%d,y=%d,w=%d,h=%d>",
|
||||
def.scanCode, def.centerX, def.centerY, def.width, def.height);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
GeckoInputReaderPolicy::getInputDeviceCalibration(const String8& deviceName, InputDeviceCalibration& outCalibration)
|
||||
{
|
||||
outCalibration.clear();
|
||||
}
|
||||
|
||||
void
|
||||
GeckoInputReaderPolicy::getExcludedDeviceNames(Vector<String8>& outExcludedDeviceNames)
|
||||
{
|
||||
outExcludedDeviceNames.clear();
|
||||
}
|
||||
|
||||
// GeckoInputDispatcher
|
||||
void
|
||||
|
@ -511,8 +405,8 @@ GeckoInputDispatcher::dispatchOnce()
|
|||
}
|
||||
sendMouseEvent(msg,
|
||||
data.timeMs,
|
||||
data.motion.touches[0].coords.x,
|
||||
data.motion.touches[0].coords.y);
|
||||
data.motion.touches[0].coords.getX(),
|
||||
data.motion.touches[0].coords.getY());
|
||||
break;
|
||||
}
|
||||
case UserInputData::KEY_DATA:
|
||||
|
@ -525,7 +419,7 @@ GeckoInputDispatcher::dispatchOnce()
|
|||
|
||||
|
||||
void
|
||||
GeckoInputDispatcher::notifyConfigurationChanged(nsecs_t eventTime)
|
||||
GeckoInputDispatcher::notifyConfigurationChanged(const NotifyConfigurationChangedArgs*)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -536,25 +430,16 @@ nanosecsToMillisecs(nsecs_t nsecs)
|
|||
}
|
||||
|
||||
void
|
||||
GeckoInputDispatcher::notifyKey(nsecs_t eventTime,
|
||||
int32_t deviceId,
|
||||
int32_t source,
|
||||
uint32_t policyFlags,
|
||||
int32_t action,
|
||||
int32_t flags,
|
||||
int32_t keyCode,
|
||||
int32_t scanCode,
|
||||
int32_t metaState,
|
||||
nsecs_t downTime)
|
||||
GeckoInputDispatcher::notifyKey(const NotifyKeyArgs* args)
|
||||
{
|
||||
UserInputData data;
|
||||
data.timeMs = nanosecsToMillisecs(eventTime);
|
||||
data.timeMs = nanosecsToMillisecs(args->eventTime);
|
||||
data.type = UserInputData::KEY_DATA;
|
||||
data.action = action;
|
||||
data.flags = flags;
|
||||
data.metaState = metaState;
|
||||
data.key.keyCode = keyCode;
|
||||
data.key.scanCode = scanCode;
|
||||
data.action = args->action;
|
||||
data.flags = args->flags;
|
||||
data.metaState = args->metaState;
|
||||
data.key.keyCode = args->keyCode;
|
||||
data.key.scanCode = args->scanCode;
|
||||
{
|
||||
MutexAutoLock lock(mQueueLock);
|
||||
mEventQueue.push(data);
|
||||
|
@ -562,34 +447,22 @@ GeckoInputDispatcher::notifyKey(nsecs_t eventTime,
|
|||
gAppShell->NotifyNativeEvent();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
GeckoInputDispatcher::notifyMotion(nsecs_t eventTime,
|
||||
int32_t deviceId,
|
||||
int32_t source,
|
||||
uint32_t policyFlags,
|
||||
int32_t action,
|
||||
int32_t flags,
|
||||
int32_t metaState,
|
||||
int32_t edgeFlags,
|
||||
uint32_t pointerCount,
|
||||
const int32_t* pointerIds,
|
||||
const PointerCoords* pointerCoords,
|
||||
float xPrecision,
|
||||
float yPrecision,
|
||||
nsecs_t downTime)
|
||||
GeckoInputDispatcher::notifyMotion(const NotifyMotionArgs* args)
|
||||
{
|
||||
UserInputData data;
|
||||
data.timeMs = nanosecsToMillisecs(eventTime);
|
||||
data.timeMs = nanosecsToMillisecs(args->eventTime);
|
||||
data.type = UserInputData::MOTION_DATA;
|
||||
data.action = action;
|
||||
data.flags = flags;
|
||||
data.metaState = metaState;
|
||||
MOZ_ASSERT(pointerCount <= MAX_POINTERS);
|
||||
data.motion.touchCount = pointerCount;
|
||||
for (int32_t i = 0; i < pointerCount; ++i) {
|
||||
data.action = args->action;
|
||||
data.flags = args->flags;
|
||||
data.metaState = args->metaState;
|
||||
MOZ_ASSERT(args->pointerCount <= MAX_POINTERS);
|
||||
data.motion.touchCount = args->pointerCount;
|
||||
for (uint32_t i = 0; i < args->pointerCount; ++i) {
|
||||
Touch& touch = data.motion.touches[i];
|
||||
touch.id = pointerIds[i];
|
||||
memcpy(&touch.coords, &pointerCoords[i], sizeof(*pointerCoords));
|
||||
touch.id = args->pointerProperties[i].id;
|
||||
memcpy(&touch.coords, &args->pointerCoords[i], sizeof(*args->pointerCoords));
|
||||
}
|
||||
{
|
||||
MutexAutoLock lock(mQueueLock);
|
||||
|
@ -604,32 +477,31 @@ GeckoInputDispatcher::notifyMotion(nsecs_t eventTime,
|
|||
gAppShell->NotifyNativeEvent();
|
||||
}
|
||||
|
||||
void
|
||||
GeckoInputDispatcher::notifySwitch(nsecs_t when,
|
||||
int32_t switchCode,
|
||||
int32_t switchValue,
|
||||
uint32_t policyFlags)
|
||||
|
||||
|
||||
void GeckoInputDispatcher::notifySwitch(const NotifySwitchArgs* args)
|
||||
{
|
||||
}
|
||||
|
||||
void GeckoInputDispatcher::notifyDeviceReset(const NotifyDeviceResetArgs* args)
|
||||
{
|
||||
}
|
||||
|
||||
int32_t
|
||||
GeckoInputDispatcher::injectInputEvent(const InputEvent* event,
|
||||
int32_t injectorPid,
|
||||
int32_t injectorUid,
|
||||
int32_t syncMode,
|
||||
int32_t timeoutMillis)
|
||||
int32_t GeckoInputDispatcher::injectInputEvent(
|
||||
const InputEvent* event,
|
||||
int32_t injectorPid, int32_t injectorUid, int32_t syncMode,
|
||||
int32_t timeoutMillis, uint32_t policyFlags)
|
||||
{
|
||||
return INPUT_EVENT_INJECTION_SUCCEEDED;
|
||||
}
|
||||
|
||||
void
|
||||
GeckoInputDispatcher::setInputWindows(const Vector<InputWindow>& inputWindows)
|
||||
GeckoInputDispatcher::setInputWindows(const Vector<sp<InputWindowHandle> >& inputWindowHandles)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
GeckoInputDispatcher::setFocusedApplication(const InputApplication* inputApplication)
|
||||
GeckoInputDispatcher::setFocusedApplication(const sp<InputApplicationHandle>& inputApplicationHandle)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -640,7 +512,7 @@ GeckoInputDispatcher::setInputDispatchMode(bool enabled, bool frozen)
|
|||
|
||||
status_t
|
||||
GeckoInputDispatcher::registerInputChannel(const sp<InputChannel>& inputChannel,
|
||||
bool monitor)
|
||||
const sp<InputWindowHandle>& inputWindowHandle, bool monitor)
|
||||
{
|
||||
return OK;
|
||||
}
|
||||
|
@ -747,16 +619,26 @@ nsAppShell::Init()
|
|||
rv = AddFdHandler(signalfds[0], pipeHandler, "");
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// Delay initializing input devices until the screen has been
|
||||
// initialized (and we know the resolution).
|
||||
return rv;
|
||||
}
|
||||
|
||||
void
|
||||
nsAppShell::InitInputDevices()
|
||||
{
|
||||
mEventHub = new EventHub();
|
||||
mReaderPolicy = new GeckoInputReaderPolicy();
|
||||
mReaderPolicy->setDisplayInfo();
|
||||
mDispatcher = new GeckoInputDispatcher();
|
||||
|
||||
mReader = new InputReader(mEventHub, mReaderPolicy, mDispatcher);
|
||||
mReaderThread = new InputReaderThread(mReader);
|
||||
|
||||
status_t result = mReaderThread->run("InputReader", PRIORITY_URGENT_DISPLAY);
|
||||
NS_ENSURE_FALSE(result, NS_ERROR_UNEXPECTED);
|
||||
return rv;
|
||||
if (result) {
|
||||
LOG("Failed to initialize InputReader thread, bad things are going to happen...");
|
||||
}
|
||||
}
|
||||
|
||||
nsresult
|
||||
|
@ -820,3 +702,8 @@ nsAppShell::NotifyNativeEvent()
|
|||
write(signalfds[1], "w", 1);
|
||||
}
|
||||
|
||||
/*static*/ void
|
||||
nsAppShell::NotifyScreenInitialized()
|
||||
{
|
||||
gAppShell->InitInputDevices();
|
||||
}
|
||||
|
|
|
@ -97,6 +97,8 @@ public:
|
|||
|
||||
void NotifyNativeEvent();
|
||||
|
||||
static void NotifyScreenInitialized();
|
||||
|
||||
protected:
|
||||
virtual ~nsAppShell();
|
||||
|
||||
|
@ -105,6 +107,7 @@ protected:
|
|||
private:
|
||||
nsresult AddFdHandler(int fd, FdHandlerCallback handlerFunc,
|
||||
const char* deviceName);
|
||||
void InitInputDevices();
|
||||
|
||||
// This is somewhat racy but is perfectly safe given how the callback works
|
||||
bool mNativeCallbackRequest;
|
||||
|
|
|
@ -100,6 +100,8 @@ nsWindow::nsWindow()
|
|||
}
|
||||
}
|
||||
sVirtualBounds = gScreenBounds;
|
||||
|
||||
nsAppShell::NotifyScreenInitialized();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче