diff options
author | The Android Open Source Project <initial-contribution@android.com> | 2008-10-21 07:00:00 -0700 |
---|---|---|
committer | The Android Open Source Project <initial-contribution@android.com> | 2008-10-21 07:00:00 -0700 |
commit | 54b6cfa9a9e5b861a9930af873580d6dc20f773c (patch) | |
tree | 35051494d2af230dce54d6b31c6af8fc24091316 /libs/ui | |
download | frameworks_base-54b6cfa9a9e5b861a9930af873580d6dc20f773c.zip frameworks_base-54b6cfa9a9e5b861a9930af873580d6dc20f773c.tar.gz frameworks_base-54b6cfa9a9e5b861a9930af873580d6dc20f773c.tar.bz2 |
Initial Contribution
Diffstat (limited to 'libs/ui')
28 files changed, 6763 insertions, 0 deletions
diff --git a/libs/ui/Android.mk b/libs/ui/Android.mk new file mode 100644 index 0000000..71579c5 --- /dev/null +++ b/libs/ui/Android.mk @@ -0,0 +1,39 @@ +LOCAL_PATH:= $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_SRC_FILES:= \ + BlitHardware.cpp \ + Camera.cpp \ + CameraParameters.cpp \ + EGLDisplaySurface.cpp \ + EGLNativeWindowSurface.cpp \ + EventHub.cpp \ + EventRecurrence.cpp \ + KeyLayoutMap.cpp \ + KeyCharacterMap.cpp \ + ICamera.cpp \ + ICameraClient.cpp \ + ICameraService.cpp \ + ISurfaceComposer.cpp \ + ISurface.cpp \ + ISurfaceFlingerClient.cpp \ + LayerState.cpp \ + PixelFormat.cpp \ + Point.cpp \ + Rect.cpp \ + Region.cpp \ + Surface.cpp \ + SurfaceComposerClient.cpp \ + SurfaceFlingerSynchro.cpp \ + Time.cpp + +LOCAL_SHARED_LIBRARIES := \ + libcorecg \ + libcutils \ + libutils \ + libpixelflinger \ + libhardware + +LOCAL_MODULE:= libui + +include $(BUILD_SHARED_LIBRARY) diff --git a/libs/ui/BlitHardware.cpp b/libs/ui/BlitHardware.cpp new file mode 100644 index 0000000..90838b4 --- /dev/null +++ b/libs/ui/BlitHardware.cpp @@ -0,0 +1,446 @@ +/* + * 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 "SurfaceFlinger" + +#include <stdint.h> +#include <string.h> +#include <unistd.h> +#include <fcntl.h> + +#include <sys/ioctl.h> +#include <sys/types.h> +#include <sys/mman.h> + +#include <cutils/log.h> + +#include <utils/Errors.h> + +#if HAVE_ANDROID_OS +#include <linux/fb.h> +#include <linux/msm_mdp.h> +#endif + +#include <ui/BlitHardware.h> + +/******************************************************************************/ + +namespace android { +class CopybitMSM7K : public copybit_t { +public: + CopybitMSM7K(); + ~CopybitMSM7K(); + + status_t getStatus() const { + if (mFD<0) return mFD; + return NO_ERROR; + } + + status_t setParameter(int name, int value); + + status_t get(int name); + + status_t blit( + const copybit_image_t& dst, + const copybit_image_t& src, + copybit_region_t const* region); + + status_t stretch( + const copybit_image_t& dst, + const copybit_image_t& src, + const copybit_rect_t& dst_rect, + const copybit_rect_t& src_rect, + copybit_region_t const* region); + +#if HAVE_ANDROID_OS +private: + static int copybit_set_parameter(copybit_t* handle, int name, int value); + static int copybit_blit( copybit_t* handle, + copybit_image_t const* dst, copybit_image_t const* src, + copybit_region_t const* region); + static int copybit_stretch(copybit_t* handle, + copybit_image_t const* dst, copybit_image_t const* src, + copybit_rect_t const* dst_rect, copybit_rect_t const* src_rect, + copybit_region_t const* region); + static int copybit_get(copybit_t* handle, int name); + + int getFormat(int format); + void setImage(mdp_img* img, const copybit_image_t& rhs); + void setRects(mdp_blit_req* req, const copybit_rect_t& dst, + const copybit_rect_t& src, const copybit_rect_t& scissor); + void setInfos(mdp_blit_req* req); + static void intersect(copybit_rect_t* out, + const copybit_rect_t& lhs, const copybit_rect_t& rhs); + status_t msm_copybit(void const* list); +#endif + int mFD; + uint8_t mAlpha; + uint8_t mFlags; +}; +}; // namespace android + +using namespace android; + +/******************************************************************************/ + +struct copybit_t* copybit_init() +{ + CopybitMSM7K* engine = new CopybitMSM7K(); + if (engine->getStatus() != NO_ERROR) { + delete engine; + engine = 0; + } + return (struct copybit_t*)engine; + +} + +int copybit_term(copybit_t* handle) +{ + delete static_cast<CopybitMSM7K*>(handle); + return NO_ERROR; +} + +namespace android { +/******************************************************************************/ + +static inline +int min(int a, int b) { + return (a<b) ? a : b; +} + +static inline +int max(int a, int b) { + return (a>b) ? a : b; +} + +static inline +void MULDIV(uint32_t& a, uint32_t& b, int mul, int div) +{ + if (mul != div) { + a = (mul * a) / div; + b = (mul * b) / div; + } +} + +//----------------------------------------------------------------------------- + +#if HAVE_ANDROID_OS + +int CopybitMSM7K::copybit_set_parameter(copybit_t* handle, int name, int value) +{ + return static_cast<CopybitMSM7K*>(handle)->setParameter(name, value); +} + +int CopybitMSM7K::copybit_get(copybit_t* handle, int name) +{ + return static_cast<CopybitMSM7K*>(handle)->get(name); +} + +int CopybitMSM7K::copybit_blit( + copybit_t* handle, + copybit_image_t const* dst, + copybit_image_t const* src, + struct copybit_region_t const* region) +{ + return static_cast<CopybitMSM7K*>(handle)->blit(*dst, *src, region); +} + +int CopybitMSM7K::copybit_stretch( + copybit_t* handle, + copybit_image_t const* dst, + copybit_image_t const* src, + copybit_rect_t const* dst_rect, + copybit_rect_t const* src_rect, + struct copybit_region_t const* region) +{ + return static_cast<CopybitMSM7K*>(handle)->stretch( + *dst, *src, *dst_rect, *src_rect, region); +} + +//----------------------------------------------------------------------------- + +CopybitMSM7K::CopybitMSM7K() + : mFD(-1), mAlpha(MDP_ALPHA_NOP), mFlags(0) +{ + int fd = open("/dev/graphics/fb0", O_RDWR, 0); + if (fd > 0) { + struct fb_fix_screeninfo finfo; + if (ioctl(fd, FBIOGET_FSCREENINFO, &finfo) == 0) { + if (!strcmp(finfo.id, "msmfb")) { + mFD = fd; + copybit_t::set_parameter = copybit_set_parameter; + copybit_t::get = copybit_get; + copybit_t::blit = copybit_blit; + copybit_t::stretch = copybit_stretch; + } + } + } + if (fd<0 || mFD<0) { + if (fd>0) { close(fd); } + mFD = -errno; + } +} + +CopybitMSM7K::~CopybitMSM7K() +{ + if (mFD > 0){ + close(mFD); + } +} + +status_t CopybitMSM7K::setParameter(int name, int value) +{ + switch(name) { + case COPYBIT_ROTATION_DEG: + switch (value) { + case 0: + mFlags &= ~0x7; + break; + case 90: + mFlags &= ~0x7; + mFlags |= MDP_ROT_90; + break; + case 180: + mFlags &= ~0x7; + mFlags |= MDP_ROT_180; + break; + case 270: + mFlags &= ~0x7; + mFlags |= MDP_ROT_270; + break; + default: + return BAD_VALUE; + } + break; + case COPYBIT_PLANE_ALPHA: + if (value < 0) value = 0; + if (value >= 256) value = 255; + mAlpha = value; + break; + case COPYBIT_DITHER: + if (value == COPYBIT_ENABLE) { + mFlags |= MDP_DITHER; + } else if (value == COPYBIT_DISABLE) { + mFlags &= ~MDP_DITHER; + } + break; + case COPYBIT_TRANSFORM: + mFlags &= ~0x7; + mFlags |= value & 0x7; + break; + default: + return BAD_VALUE; + } + return NO_ERROR; +} + +status_t CopybitMSM7K::get(int name) +{ + switch(name) { + case COPYBIT_MINIFICATION_LIMIT: + return 4; + case COPYBIT_MAGNIFICATION_LIMIT: + return 4; + case COPYBIT_SCALING_FRAC_BITS: + return 32; + case COPYBIT_ROTATION_STEP_DEG: + return 90; + } + return BAD_VALUE; +} + +status_t CopybitMSM7K::blit( + const copybit_image_t& dst, + const copybit_image_t& src, + copybit_region_t const* region) +{ + + copybit_rect_t dr = { 0, 0, dst.w, dst.h }; + copybit_rect_t sr = { 0, 0, src.w, src.h }; + return CopybitMSM7K::stretch(dst, src, dr, sr, region); +} + +status_t CopybitMSM7K::stretch( + const copybit_image_t& dst, + const copybit_image_t& src, + const copybit_rect_t& dst_rect, + const copybit_rect_t& src_rect, + copybit_region_t const* region) +{ + struct { + uint32_t count; + struct mdp_blit_req req[12]; + } list; + + if (mAlpha<255) { + switch (src.format) { + // we dont' support plane alpha with RGBA formats + case COPYBIT_RGBA_8888: + case COPYBIT_RGBA_5551: + case COPYBIT_RGBA_4444: + return INVALID_OPERATION; + } + } + + const uint32_t maxCount = sizeof(list.req)/sizeof(list.req[0]); + const copybit_rect_t bounds = { 0, 0, dst.w, dst.h }; + copybit_rect_t clip; + list.count = 0; + int err = 0; + while (!err && region->next(region, &clip)) { + intersect(&clip, bounds, clip); + setInfos(&list.req[list.count]); + setImage(&list.req[list.count].dst, dst); + setImage(&list.req[list.count].src, src); + setRects(&list.req[list.count], dst_rect, src_rect, clip); + if (++list.count == maxCount) { + err = msm_copybit(&list); + list.count = 0; + } + } + if (!err && list.count) { + err = msm_copybit(&list); + } + return err; +} + +status_t CopybitMSM7K::msm_copybit(void const* list) +{ + int err = ioctl(mFD, MSMFB_BLIT, static_cast<mdp_blit_req_list const*>(list)); + LOGE_IF(err<0, "copyBits failed (%s)", strerror(errno)); + if (err == 0) + return NO_ERROR; + return -errno; +} + +int CopybitMSM7K::getFormat(int format) +{ + switch (format) { + case COPYBIT_RGBA_8888: return MDP_RGBA_8888; + case COPYBIT_RGB_565: return MDP_RGB_565; + case COPYBIT_YCbCr_422_SP: return MDP_Y_CBCR_H2V1; + case COPYBIT_YCbCr_420_SP: return MDP_Y_CBCR_H2V2; + } + return -1; +} + +void CopybitMSM7K::setInfos(mdp_blit_req* req) +{ + req->alpha = mAlpha; + req->transp_mask = MDP_TRANSP_NOP; + req->flags = mFlags; +} + +void CopybitMSM7K::setImage(mdp_img* img, const copybit_image_t& rhs) +{ + img->width = rhs.w; + img->height = rhs.h; + img->format = getFormat(rhs.format); + img->offset = rhs.offset; + img->memory_id = rhs.fd; +} + +void CopybitMSM7K::setRects(mdp_blit_req* e, + const copybit_rect_t& dst, const copybit_rect_t& src, + const copybit_rect_t& scissor) +{ + copybit_rect_t clip; + intersect(&clip, scissor, dst); + + e->dst_rect.x = clip.l; + e->dst_rect.y = clip.t; + e->dst_rect.w = clip.r - clip.l; + e->dst_rect.h = clip.b - clip.t; + + uint32_t W, H; + if (mFlags & COPYBIT_TRANSFORM_ROT_90) { + e->src_rect.x = (clip.t - dst.t) + src.t; + e->src_rect.y = (dst.r - clip.r) + src.l; + e->src_rect.w = (clip.b - clip.t); + e->src_rect.h = (clip.r - clip.l); + W = dst.b - dst.t; + H = dst.r - dst.l; + } else { + e->src_rect.x = (clip.l - dst.l) + src.l; + e->src_rect.y = (clip.t - dst.t) + src.t; + e->src_rect.w = (clip.r - clip.l); + e->src_rect.h = (clip.b - clip.t); + W = dst.r - dst.l; + H = dst.b - dst.t; + } + MULDIV(e->src_rect.x, e->src_rect.w, src.r - src.l, W); + MULDIV(e->src_rect.y, e->src_rect.h, src.b - src.t, H); + if (mFlags & COPYBIT_TRANSFORM_FLIP_V) { + e->src_rect.y = e->src.height - (e->src_rect.y + e->src_rect.h); + } + if (mFlags & COPYBIT_TRANSFORM_FLIP_H) { + e->src_rect.x = e->src.width - (e->src_rect.x + e->src_rect.w); + } +} + +void CopybitMSM7K::intersect(copybit_rect_t* out, + const copybit_rect_t& lhs, const copybit_rect_t& rhs) +{ + out->l = max(lhs.l, rhs.l); + out->t = max(lhs.t, rhs.t); + out->r = min(lhs.r, rhs.r); + out->b = min(lhs.b, rhs.b); +} + +/******************************************************************************/ +#else // HAVE_ANDROID_OS + +CopybitMSM7K::CopybitMSM7K() + : mFD(-1) +{ +} + +CopybitMSM7K::~CopybitMSM7K() +{ +} + +status_t CopybitMSM7K::setParameter(int name, int value) +{ + return NO_INIT; +} + +status_t CopybitMSM7K::get(int name) +{ + return BAD_VALUE; +} + +status_t CopybitMSM7K::blit( + const copybit_image_t& dst, + const copybit_image_t& src, + copybit_region_t const* region) +{ + return NO_INIT; +} + +status_t CopybitMSM7K::stretch( + const copybit_image_t& dst, + const copybit_image_t& src, + const copybit_rect_t& dst_rect, + const copybit_rect_t& src_rect, + copybit_region_t const* region) +{ + return NO_INIT; +} + +#endif // HAVE_ANDROID_OS + +/******************************************************************************/ +}; // namespace android diff --git a/libs/ui/Camera.cpp b/libs/ui/Camera.cpp new file mode 100644 index 0000000..1528e6e --- /dev/null +++ b/libs/ui/Camera.cpp @@ -0,0 +1,249 @@ +/* +** +** Copyright 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 "Camera" +#include <utils/Log.h> + +#include <utils/IServiceManager.h> +#include <utils/threads.h> +#include <utils/IMemory.h> +#include <ui/Surface.h> + +#include <ui/Camera.h> +#include <ui/ICameraService.h> + +namespace android { + +// client singleton for camera service binder interface +Mutex Camera::mLock; +sp<ICameraService> Camera::mCameraService; +sp<Camera::DeathNotifier> Camera::mDeathNotifier; + +// establish binder interface to camera service +const sp<ICameraService>& Camera::getCameraService() +{ + Mutex::Autolock _l(mLock); + if (mCameraService.get() == 0) { + sp<IServiceManager> sm = defaultServiceManager(); + sp<IBinder> binder; + do { + binder = sm->getService(String16("media.camera")); + if (binder != 0) + break; + LOGW("CameraService not published, waiting..."); + usleep(500000); // 0.5 s + } while(true); + if (mDeathNotifier == NULL) { + mDeathNotifier = new DeathNotifier(); + } + binder->linkToDeath(mDeathNotifier); + mCameraService = interface_cast<ICameraService>(binder); + } + LOGE_IF(mCameraService==0, "no CameraService!?"); + return mCameraService; +} + +// --------------------------------------------------------------------------- + +Camera::Camera() + : mStatus(UNKNOWN_ERROR), + mShutterCallback(0), + mShutterCallbackCookie(0), + mRawCallback(0), + mRawCallbackCookie(0), + mJpegCallback(0), + mJpegCallbackCookie(0), + mFrameCallback(0), + mFrameCallbackCookie(0), + mErrorCallback(0), + mErrorCallbackCookie(0), + mAutoFocusCallback(0), + mAutoFocusCallbackCookie(0) +{ +} + +Camera::~Camera() +{ + disconnect(); +} + +sp<Camera> Camera::connect() +{ + sp<Camera> c = new Camera(); + const sp<ICameraService>& cs = getCameraService(); + if (cs != 0) { + c->mCamera = cs->connect(c); + } + if (c->mCamera != 0) { + c->mCamera->asBinder()->linkToDeath(c); + c->mStatus = NO_ERROR; + } + return c; +} + +void Camera::disconnect() +{ + if (mCamera != 0) { + mErrorCallback = 0; + mCamera->disconnect(); + mCamera = 0; + } +} + +// pass the buffered ISurface to the camera service +status_t Camera::setPreviewDisplay(const sp<Surface>& surface) +{ + if (surface == 0) { + LOGE("app passed NULL surface"); + return NO_INIT; + } + return mCamera->setPreviewDisplay(surface->getISurface()); +} + +// start preview mode, must call setPreviewDisplay first +status_t Camera::startPreview() +{ + return mCamera->startPreview(); +} + +// stop preview mode +void Camera::stopPreview() +{ + mCamera->stopPreview(); +} + +status_t Camera::autoFocus() +{ + return mCamera->autoFocus(); +} + +// take a picture +status_t Camera::takePicture() +{ + return mCamera->takePicture(); +} + +// set preview/capture parameters - key/value pairs +status_t Camera::setParameters(const String8& params) +{ + return mCamera->setParameters(params); +} + +// get preview/capture parameters - key/value pairs +String8 Camera::getParameters() const +{ + String8 params = mCamera->getParameters(); + return params; +} + +void Camera::setAutoFocusCallback(autofocus_callback cb, void *cookie) +{ + mAutoFocusCallback = cb; + mAutoFocusCallbackCookie = cookie; +} + +void Camera::setShutterCallback(shutter_callback cb, void *cookie) +{ + mShutterCallback = cb; + mShutterCallbackCookie = cookie; +} + +void Camera::setRawCallback(frame_callback cb, void *cookie) +{ + mRawCallback = cb; + mRawCallbackCookie = cookie; +} + +void Camera::setJpegCallback(frame_callback cb, void *cookie) +{ + mJpegCallback = cb; + mJpegCallbackCookie = cookie; +} + +void Camera::setFrameCallback(frame_callback cb, void *cookie) +{ + mFrameCallback = cb; + mFrameCallbackCookie = cookie; + mCamera->setHasFrameCallback(cb != NULL); +} + +void Camera::setErrorCallback(error_callback cb, void *cookie) +{ + mErrorCallback = cb; + mErrorCallbackCookie = cookie; +} + +void Camera::autoFocusCallback(bool focused) +{ + if (mAutoFocusCallback) { + mAutoFocusCallback(focused, mAutoFocusCallbackCookie); + } +} + +void Camera::shutterCallback() +{ + if (mShutterCallback) { + mShutterCallback(mShutterCallbackCookie); + } +} + +void Camera::rawCallback(const sp<IMemory>& picture) +{ + if (mRawCallback) { + mRawCallback(picture, mRawCallbackCookie); + } +} + +// callback from camera service when image is ready +void Camera::jpegCallback(const sp<IMemory>& picture) +{ + if (mJpegCallback) { + mJpegCallback(picture, mJpegCallbackCookie); + } +} + +// callback from camera service when video frame is ready +void Camera::frameCallback(const sp<IMemory>& frame) +{ + if (mFrameCallback) { + mFrameCallback(frame, mFrameCallbackCookie); + } +} + +// callback from camera service when an error occurs in preview or takePicture +void Camera::errorCallback(status_t error) +{ + if (mErrorCallback) { + mErrorCallback(error, mErrorCallbackCookie); + } +} + +void Camera::binderDied(const wp<IBinder>& who) { + LOGW("ICamera died"); + if (mErrorCallback) { + mErrorCallback(DEAD_OBJECT, mErrorCallbackCookie); + } +} + +void Camera::DeathNotifier::binderDied(const wp<IBinder>& who) { + Mutex::Autolock _l(Camera::mLock); + Camera::mCameraService.clear(); + LOGW("Camera server died!"); +} + +}; // namespace android + diff --git a/libs/ui/CameraParameters.cpp b/libs/ui/CameraParameters.cpp new file mode 100644 index 0000000..7ca77bb --- /dev/null +++ b/libs/ui/CameraParameters.cpp @@ -0,0 +1,253 @@ +/* +** +** Copyright 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 "CameraParams" +#include <utils/Log.h> + +#include <string.h> +#include <stdlib.h> +#include <ui/CameraParameters.h> + +namespace android { + +CameraParameters::CameraParameters() + : mMap() +{ +} + +CameraParameters::~CameraParameters() +{ +} + +String8 CameraParameters::flatten() const +{ + String8 flattened(""); + size_t size = mMap.size(); + + for (size_t i = 0; i < size; i++) { + String8 k, v; + k = mMap.keyAt(i); + v = mMap.valueAt(i); + + flattened += k; + flattened += "="; + flattened += v; + if (i != size-1) + flattened += ";"; + } + + return flattened; +} + +void CameraParameters::unflatten(const String8 ¶ms) +{ + const char *a = params.string(); + const char *b; + + mMap.clear(); + + for (;;) { + // Find the bounds of the key name. + b = strchr(a, '='); + if (b == 0) + break; + + // Create the key string. + String8 k(a, (size_t)(b-a)); + + // Find the value. + a = b+1; + b = strchr(a, ';'); + if (b == 0) { + // If there's no semicolon, this is the last item. + String8 v(a); + mMap.add(k, v); + break; + } + + String8 v(a, (size_t)(b-a)); + mMap.add(k, v); + a = b+1; + } +} + + +void CameraParameters::set(const char *key, const char *value) +{ + // XXX i think i can do this with strspn() + if (strchr(key, '=') || strchr(key, ';')) { + //XXX LOGE("Key \"%s\"contains invalid character (= or ;)", key); + return; + } + + if (strchr(value, '=') || strchr(key, ';')) { + //XXX LOGE("Value \"%s\"contains invalid character (= or ;)", value); + return; + } + + mMap.replaceValueFor(String8(key), String8(value)); +} + +void CameraParameters::set(const char *key, int value) +{ + char str[16]; + sprintf(str, "%d", value); + set(key, str); +} + +const char *CameraParameters::get(const char *key) const +{ + String8 v = mMap.valueFor(String8(key)); + if (v.length() == 0) + return 0; + return v.string(); +} + +int CameraParameters::getInt(const char *key) const +{ + const char *v = get(key); + if (v == 0) + return -1; + return strtol(v, 0, 0); +} + +static int parse_size(const char *str, int &width, int &height) +{ + // Find the width. + char *end; + int w = (int)strtol(str, &end, 10); + // If an 'x' does not immediately follow, give up. + if (*end != 'x') + return -1; + + // Find the height, immediately after the 'x'. + int h = (int)strtol(end+1, 0, 10); + + width = w; + height = h; + + return 0; +} + +void CameraParameters::setPreviewSize(int width, int height) +{ + char str[32]; + sprintf(str, "%dx%d", width, height); + set("preview-size", str); +} + +void CameraParameters::getPreviewSize(int *width, int *height) const +{ + *width = -1; + *height = -1; + + // Get the current string, if it doesn't exist, leave the -1x-1 + const char *p = get("preview-size"); + if (p == 0) + return; + + int w, h; + if (parse_size(p, w, h) == 0) { + *width = w; + *height = h; + } +} + +void CameraParameters::setPreviewFrameRate(int fps) +{ + set("preview-frame-rate", fps); +} + +int CameraParameters::getPreviewFrameRate() const +{ + return getInt("preview-frame-rate"); +} + +void CameraParameters::setPreviewFormat(const char *format) +{ + set("preview-format", format); +} + +const char *CameraParameters::getPreviewFormat() const +{ + return get("preview-format"); +} + +void CameraParameters::setPictureSize(int width, int height) +{ + char str[32]; + sprintf(str, "%dx%d", width, height); + set("picture-size", str); +} + +void CameraParameters::getPictureSize(int *width, int *height) const +{ + *width = -1; + *height = -1; + + // Get the current string, if it doesn't exist, leave the -1x-1 + const char *p = get("picture-size"); + if (p == 0) + return; + + int w, h; + if (parse_size(p, w, h) == 0) { + *width = w; + *height = h; + } +} + +void CameraParameters::setPictureFormat(const char *format) +{ + set("picture-format", format); +} + +const char *CameraParameters::getPictureFormat() const +{ + return get("picture-format"); +} + +void CameraParameters::dump() const +{ + LOGD("dump: mMap.size = %d", mMap.size()); + for (size_t i = 0; i < mMap.size(); i++) { + String8 k, v; + k = mMap.keyAt(i); + v = mMap.valueAt(i); + LOGD("%s: %s\n", k.string(), v.string()); + } +} + +status_t CameraParameters::dump(int fd, const Vector<String16>& args) const +{ + const size_t SIZE = 256; + char buffer[SIZE]; + String8 result; + snprintf(buffer, 255, "CameraParameters::dump: mMap.size = %d\n", mMap.size()); + result.append(buffer); + for (size_t i = 0; i < mMap.size(); i++) { + String8 k, v; + k = mMap.keyAt(i); + v = mMap.valueAt(i); + snprintf(buffer, 255, "\t%s: %s\n", k.string(), v.string()); + result.append(buffer); + } + write(fd, result.string(), result.size()); + return NO_ERROR; +} + +}; // namespace android diff --git a/libs/ui/EGLDisplaySurface.cpp b/libs/ui/EGLDisplaySurface.cpp new file mode 100644 index 0000000..ea245f5 --- /dev/null +++ b/libs/ui/EGLDisplaySurface.cpp @@ -0,0 +1,471 @@ +/* + ** + ** Copyright 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. + */ + +#define LOG_TAG "EGLDisplaySurface" + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <unistd.h> +#include <fcntl.h> +#include <sys/ioctl.h> +#include <sys/types.h> +#include <sys/mman.h> + +#include <cutils/log.h> +#include <cutils/atomic.h> + +#include <ui/SurfaceComposerClient.h> +#include <ui/DisplayInfo.h> +#include <ui/Rect.h> +#include <ui/Region.h> + +#if HAVE_ANDROID_OS +#include <linux/msm_mdp.h> +#endif + +#include <GLES/egl.h> + +#include <pixelflinger/format.h> + +#include <ui/EGLDisplaySurface.h> + +// ---------------------------------------------------------------------------- + +egl_native_window_t* android_createDisplaySurface() +{ + egl_native_window_t* s = new android::EGLDisplaySurface(); + s->memory_type = NATIVE_MEMORY_TYPE_GPU; + return s; +} + +#define LIKELY( exp ) (__builtin_expect( (exp) != 0, true )) +#define UNLIKELY( exp ) (__builtin_expect( (exp) != 0, false )) + +// ---------------------------------------------------------------------------- +namespace android { +// ---------------------------------------------------------------------------- + +EGLDisplaySurface::EGLDisplaySurface() + : EGLNativeSurface<EGLDisplaySurface>() +{ + egl_native_window_t::version = sizeof(egl_native_window_t); + egl_native_window_t::ident = 0; + egl_native_window_t::incRef = &EGLDisplaySurface::hook_incRef; + egl_native_window_t::decRef = &EGLDisplaySurface::hook_decRef; + egl_native_window_t::swapBuffers = &EGLDisplaySurface::hook_swapBuffers; + egl_native_window_t::setSwapRectangle = &EGLDisplaySurface::hook_setSwapRectangle; + egl_native_window_t::nextBuffer = &EGLDisplaySurface::hook_nextBuffer; + egl_native_window_t::connect = 0; + egl_native_window_t::disconnect = 0; + + mFb[0].data = 0; + mFb[1].data = 0; + mBlitEngine = 0; + egl_native_window_t::fd = mapFrameBuffer(); + if (egl_native_window_t::fd >= 0) { + mBlitEngine = copybit_init(); + const float in2mm = 25.4f; + float refreshRate = 1000000000000000LLU / ( + float( mInfo.upper_margin + mInfo.lower_margin + mInfo.yres ) + * ( mInfo.left_margin + mInfo.right_margin + mInfo.xres ) + * mInfo.pixclock); + + const GGLSurface& buffer = mFb[1 - mIndex]; + egl_native_window_t::width = buffer.width; + egl_native_window_t::height = buffer.height; + egl_native_window_t::stride = buffer.stride; + egl_native_window_t::format = buffer.format; + egl_native_window_t::base = intptr_t(mFb[0].data); + egl_native_window_t::offset = + intptr_t(buffer.data) - egl_native_window_t::base; + egl_native_window_t::flags = 0; + egl_native_window_t::xdpi = (mInfo.xres * in2mm) / mInfo.width; + egl_native_window_t::ydpi = (mInfo.yres * in2mm) / mInfo.height; + egl_native_window_t::fps = refreshRate; + egl_native_window_t::memory_type = NATIVE_MEMORY_TYPE_FB; + // no error, set the magic word + egl_native_window_t::magic = 0x600913; + } + mSwapCount = -1; + mPageFlipCount = 0; +} + +EGLDisplaySurface::~EGLDisplaySurface() +{ + magic = 0; + copybit_term(mBlitEngine); + mBlitEngine = 0; + close(egl_native_window_t::fd); + munmap(mFb[0].data, mSize); + if (!(mFlags & PAGE_FLIP)) + free((void*)mFb[1].data); +} + +void EGLDisplaySurface::hook_incRef(NativeWindowType window) { + EGLDisplaySurface* that = static_cast<EGLDisplaySurface*>(window); + that->incStrong(that); +} +void EGLDisplaySurface::hook_decRef(NativeWindowType window) { + EGLDisplaySurface* that = static_cast<EGLDisplaySurface*>(window); + that->decStrong(that); +} +uint32_t EGLDisplaySurface::hook_swapBuffers(NativeWindowType window) { + EGLDisplaySurface* that = static_cast<EGLDisplaySurface*>(window); + return that->swapBuffers(); +} +uint32_t EGLDisplaySurface::hook_nextBuffer(NativeWindowType window) { + EGLDisplaySurface* that = static_cast<EGLDisplaySurface*>(window); + return that->nextBuffer(); +} +void EGLDisplaySurface::hook_setSwapRectangle(NativeWindowType window, + int l, int t, int w, int h) { + EGLDisplaySurface* that = static_cast<EGLDisplaySurface*>(window); + that->setSwapRectangle(l, t, w, h); +} + +void EGLDisplaySurface::setSwapRectangle(int l, int t, int w, int h) +{ + mInfo.reserved[0] = 0x54445055; // "UPDT"; + mInfo.reserved[1] = (uint16_t)l | ((uint32_t)t << 16); + mInfo.reserved[2] = (uint16_t)(l+w) | ((uint32_t)(t+h) << 16); +} + +uint32_t EGLDisplaySurface::swapBuffers() +{ + if (!(mFlags & PAGE_FLIP)) + return 0; + +#define SHOW_FPS 0 +#if SHOW_FPS + nsecs_t now = systemTime(); + if (mSwapCount == -1) { + mTime = now; + mSwapCount = 0; + mSleep = 0; + } else { + nsecs_t d = now-mTime; + if (d >= seconds(1)) { + double fps = (mSwapCount * double(seconds(1))) / double(d); + LOGD("%f fps, sleep=%d / frame", + fps, (int)ns2us(mSleep / mSwapCount)); + mSwapCount = 0; + mTime = now; + mSleep = 0; + } else { + mSwapCount++; + } + } +#endif + + // do the actual flip + mIndex = 1 - mIndex; + mInfo.activate = FB_ACTIVATE_VBL; + mInfo.yoffset = mIndex ? mInfo.yres : 0; + if (ioctl(egl_native_window_t::fd, FBIOPUT_VSCREENINFO, &mInfo) == -1) { + LOGE("FBIOPUT_VSCREENINFO failed"); + return 0; + } + + /* + * this is a monstrous hack: Because the h/w accelerator is not able + * to render directly into the framebuffer, we need to copy its + * internal framebuffer out to the fb. + * oem[0] is used to access the fd of internal fb. + * All this is needed only in standalone mode, in SurfaceFlinger mode + * we control where the GPU renders. + * We do this only if we have copybit, since this hack is needed only + * with msm7k. + */ + if (egl_native_window_t::memory_type == NATIVE_MEMORY_TYPE_GPU && oem[0] && mBlitEngine) { + copybit_t *copybit = mBlitEngine; + copybit_rect_t sdrect = { 0, 0, + egl_native_window_t::width, egl_native_window_t::height }; + copybit_image_t dst = { + egl_native_window_t::width, + egl_native_window_t::height, + egl_native_window_t::format, + egl_native_window_t::offset, + (void*)egl_native_window_t::base, + egl_native_window_t::fd + }; + copybit_image_t src = { + egl_native_window_t::width, + egl_native_window_t::height, + egl_native_window_t::format, // XXX: use proper format + egl_native_window_t::offset, + (void*)egl_native_window_t::base, // XXX: use proper base + egl_native_window_t::oem[0] + }; + region_iterator it(Region(Rect( + egl_native_window_t::width, egl_native_window_t::height))); + copybit->set_parameter(copybit, COPYBIT_TRANSFORM, 0); + copybit->set_parameter(copybit, COPYBIT_PLANE_ALPHA, 0xFF); + copybit->set_parameter(copybit, COPYBIT_DITHER, COPYBIT_DISABLE); + copybit->stretch(copybit, &dst, &src, &sdrect, &sdrect, &it); + } + + // update the address of the buffer to draw to next + const GGLSurface& buffer = mFb[1 - mIndex]; + egl_native_window_t::offset = + intptr_t(buffer.data) - egl_native_window_t::base; + +#if SHOW_FPS + mSleep += systemTime()-now; +#endif + + mPageFlipCount++; + + // We don't support screen-size changes for now + return 0; +} + +int32_t EGLDisplaySurface::getPageFlipCount() const +{ + return mPageFlipCount; +} + +uint32_t EGLDisplaySurface::nextBuffer() +{ + // update the address of the buffer to draw to next + const GGLSurface& buffer = mFb[mIndex]; + egl_native_window_t::offset = + intptr_t(buffer.data) - egl_native_window_t::base; + return 0; +} + +void EGLDisplaySurface::copyFrontToBack(const Region& copyback) +{ +#if HAVE_ANDROID_OS + if (mBlitEngine) { + copybit_image_t dst = { + w: egl_native_window_t::stride, + h: egl_native_window_t::height, + format: egl_native_window_t::format, + offset: mFb[1-mIndex].data - mFb[0].data, + base: (void*)egl_native_window_t::base, + fd: egl_native_window_t::fd + }; + copybit_image_t src = { + w: egl_native_window_t::stride, + h: egl_native_window_t::height, + format: egl_native_window_t::format, + offset: mFb[mIndex].data - mFb[0].data, + base: (void*)egl_native_window_t::base, + fd: egl_native_window_t::fd + }; + region_iterator it(copyback); + mBlitEngine->blit(mBlitEngine, &dst, &src, &it); + } else +#endif + { + Region::iterator iterator(copyback); + if (iterator) { + Rect r; + uint8_t* const screen_src = mFb[ mIndex].data; + uint8_t* const screen_dst = mFb[1-mIndex].data; + const size_t bpp = bytesPerPixel(egl_native_window_t::format); + const size_t bpr = egl_native_window_t::stride * bpp; + while (iterator.iterate(&r)) { + ssize_t h = r.bottom - r.top; + if (h) { + size_t size = (r.right - r.left) * bpp; + size_t o = (r.left + egl_native_window_t::stride * r.top) * bpp; + uint8_t* s = screen_src + o; + uint8_t* d = screen_dst + o; + if (size == bpr) { + size *= h; + h = 1; + } + do { + memcpy(d, s, size); + d += bpr; + s += bpr; + } while (--h > 0); + } + } + } + } +} + +status_t EGLDisplaySurface::mapFrameBuffer() +{ + char const * const device_template[] = { + "/dev/graphics/fb%u", + "/dev/fb%u", + 0 }; + int fd = -1; + int i=0; + char name[64]; + while ((fd==-1) && device_template[i]) { + snprintf(name, 64, device_template[i], 0); + fd = open(name, O_RDWR, 0); + i++; + } + if (fd < 0) + return -errno; + + struct fb_fix_screeninfo finfo; + if (ioctl(fd, FBIOGET_FSCREENINFO, &finfo) == -1) + return -errno; + + struct fb_var_screeninfo info; + if (ioctl(fd, FBIOGET_VSCREENINFO, &info) == -1) + return -errno; + + info.reserved[0] = 0; + info.reserved[1] = 0; + info.reserved[2] = 0; + info.xoffset = 0; + info.yoffset = 0; + info.yres_virtual = info.yres * 2; + info.bits_per_pixel = 16; + /* Explicitly request 5/6/5 */ + info.red.offset = 11; + info.red.length = 5; + info.green.offset = 5; + info.green.length = 6; + info.blue.offset = 0; + info.blue.length = 5; + info.transp.offset = 0; + info.transp.length = 0; + info.activate = FB_ACTIVATE_NOW; + + uint32_t flags = PAGE_FLIP; + if (ioctl(fd, FBIOPUT_VSCREENINFO, &info) == -1) { + info.yres_virtual = info.yres; + flags &= ~PAGE_FLIP; + LOGW("FBIOPUT_VSCREENINFO failed, page flipping not supported"); + } + + if (info.yres_virtual < info.yres * 2) { + info.yres_virtual = info.yres; + flags &= ~PAGE_FLIP; + LOGW("page flipping not supported (yres_virtual=%d, requested=%d)", + info.yres_virtual, info.yres*2); + } + + if (ioctl(fd, FBIOGET_VSCREENINFO, &info) == -1) + return -errno; + + int refreshRate = 1000000000000000LLU / + ( + uint64_t( info.upper_margin + info.lower_margin + info.yres ) + * ( info.left_margin + info.right_margin + info.xres ) + * info.pixclock + ); + + if (refreshRate == 0) { + // bleagh, bad info from the driver + refreshRate = 60*1000; // 60 Hz + } + + if (int(info.width) <= 0 || int(info.height) <= 0) { + // the driver doesn't return that information + // default to 160 dpi + info.width = 51; + info.height = 38; + } + + float xdpi = (info.xres * 25.4f) / info.width; + float ydpi = (info.yres * 25.4f) / info.height; + float fps = refreshRate / 1000.0f; + + LOGI( "using (fd=%d)\n" + "id = %s\n" + "xres = %d px\n" + "yres = %d px\n" + "xres_virtual = %d px\n" + "yres_virtual = %d px\n" + "bpp = %d\n" + "r = %2u:%u\n" + "g = %2u:%u\n" + "b = %2u:%u\n", + fd, + finfo.id, + info.xres, + info.yres, + info.xres_virtual, + info.yres_virtual, + info.bits_per_pixel, + info.red.offset, info.red.length, + info.green.offset, info.green.length, + info.blue.offset, info.blue.length + ); + + LOGI( "width = %d mm (%f dpi)\n" + "height = %d mm (%f dpi)\n" + "refresh rate = %.2f Hz\n", + info.width, xdpi, + info.height, ydpi, + fps + ); + + + if (ioctl(fd, FBIOGET_FSCREENINFO, &finfo) == -1) + return -errno; + + if (finfo.smem_len <= 0) + return -errno; + + /* + * Open and map the display. + */ + + void* buffer = (uint16_t*) mmap( + 0, finfo.smem_len, + PROT_READ | PROT_WRITE, + MAP_SHARED, + fd, 0); + + if (buffer == MAP_FAILED) + return -errno; + + // at least for now, always clear the fb + memset(buffer, 0, finfo.smem_len); + + uint8_t* offscreen[2]; + offscreen[0] = (uint8_t*)buffer; + if (flags & PAGE_FLIP) { + offscreen[1] = (uint8_t*)buffer + finfo.line_length*info.yres; + } else { + offscreen[1] = (uint8_t*)malloc(finfo.smem_len); + if (offscreen[1] == 0) { + munmap(buffer, finfo.smem_len); + return NO_MEMORY; + } + } + + mFlags = flags; + mInfo = info; + mFinfo = finfo; + mSize = finfo.smem_len; + mIndex = 0; + for (int i=0 ; i<2 ; i++) { + mFb[i].version = sizeof(GGLSurface); + mFb[i].width = info.xres; + mFb[i].height = info.yres; + mFb[i].stride = finfo.line_length / (info.bits_per_pixel >> 3); + mFb[i].data = (GGLubyte*)(offscreen[i]); + mFb[i].format = GGL_PIXEL_FORMAT_RGB_565; + } + return fd; +} + +// ---------------------------------------------------------------------------- +}; // namespace android +// ---------------------------------------------------------------------------- diff --git a/libs/ui/EGLNativeWindowSurface.cpp b/libs/ui/EGLNativeWindowSurface.cpp new file mode 100644 index 0000000..0b6afc0 --- /dev/null +++ b/libs/ui/EGLNativeWindowSurface.cpp @@ -0,0 +1,181 @@ +/* +** +** Copyright 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. +*/ + +#define LOG_TAG "EGLNativeWindowSurface" + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +#include <cutils/log.h> +#include <cutils/atomic.h> + +#include <ui/SurfaceComposerClient.h> +#include <ui/DisplayInfo.h> +#include <ui/Rect.h> + +#include <GLES/egl.h> + +#include <pixelflinger/format.h> + +#include <ui/EGLNativeWindowSurface.h> + +// ---------------------------------------------------------------------------- +namespace android { +// ---------------------------------------------------------------------------- + +EGLNativeWindowSurface::EGLNativeWindowSurface(const sp<Surface>& surface) + : EGLNativeSurface<EGLNativeWindowSurface>(), + mSurface(surface), mConnected(false) +{ + egl_native_window_t::magic = 0x600913; + egl_native_window_t::version = sizeof(egl_native_window_t); + egl_native_window_t::ident = 0; + egl_native_window_t::incRef = &EGLNativeWindowSurface::hook_incRef; + egl_native_window_t::decRef = &EGLNativeWindowSurface::hook_decRef; + egl_native_window_t::swapBuffers = &EGLNativeWindowSurface::hook_swapBuffers; + egl_native_window_t::nextBuffer = &EGLNativeWindowSurface::hook_nextBuffer; + egl_native_window_t::setSwapRectangle = &EGLNativeWindowSurface::hook_setSwapRectangle; + egl_native_window_t::connect = &EGLNativeWindowSurface::hook_connect; + egl_native_window_t::disconnect = &EGLNativeWindowSurface::hook_disconnect; + + DisplayInfo dinfo; + SurfaceComposerClient::getDisplayInfo(0, &dinfo); + egl_native_window_t::xdpi = dinfo.xdpi; + egl_native_window_t::ydpi = dinfo.ydpi; + egl_native_window_t::fps = dinfo.fps; + egl_native_window_t::flags= EGL_NATIVES_FLAG_DESTROY_BACKBUFFER; +} + +EGLNativeWindowSurface::~EGLNativeWindowSurface() +{ + disconnect(); + mSurface.clear(); + magic = 0; +} + +void EGLNativeWindowSurface::hook_incRef(NativeWindowType window) +{ + EGLNativeWindowSurface* that = static_cast<EGLNativeWindowSurface*>(window); + that->incStrong(that); +} + +void EGLNativeWindowSurface::hook_decRef(NativeWindowType window) +{ + EGLNativeWindowSurface* that = static_cast<EGLNativeWindowSurface*>(window); + that->decStrong(that); +} + +void EGLNativeWindowSurface::hook_connect(NativeWindowType window) +{ + EGLNativeWindowSurface* that = static_cast<EGLNativeWindowSurface*>(window); + that->connect(); +} + +void EGLNativeWindowSurface::hook_disconnect(NativeWindowType window) +{ + EGLNativeWindowSurface* that = static_cast<EGLNativeWindowSurface*>(window); + that->disconnect(); +} + +uint32_t EGLNativeWindowSurface::hook_swapBuffers(NativeWindowType window) +{ + EGLNativeWindowSurface* that = static_cast<EGLNativeWindowSurface*>(window); + return that->swapBuffers(); +} + +uint32_t EGLNativeWindowSurface::hook_nextBuffer(NativeWindowType window) +{ + EGLNativeWindowSurface* that = static_cast<EGLNativeWindowSurface*>(window); + return that->nextBuffer(); +} + +void EGLNativeWindowSurface::hook_setSwapRectangle(NativeWindowType window, int l, int t, int w, int h) +{ + EGLNativeWindowSurface* that = static_cast<EGLNativeWindowSurface*>(window); + that->setSwapRectangle(l, t, w, h); +} + +void EGLNativeWindowSurface::setSwapRectangle(int l, int t, int w, int h) +{ + mSurface->setSwapRectangle(Rect(l, t, l+w, t+h)); +} + +uint32_t EGLNativeWindowSurface::swapBuffers() +{ + const int w = egl_native_window_t::width; + const int h = egl_native_window_t::height; + const sp<Surface>& surface(mSurface); + Surface::SurfaceInfo info; + surface->unlockAndPost(); + surface->lock(&info); + // update the address of the buffer to draw to next + egl_native_window_t::base = intptr_t(info.base); + egl_native_window_t::offset = intptr_t(info.bits) - intptr_t(info.base); + + // update size if it changed + if (w != int(info.w) || h != int(info.h)) { + egl_native_window_t::width = info.w; + egl_native_window_t::height = info.h; + egl_native_window_t::stride = info.bpr / bytesPerPixel(info.format); + egl_native_window_t::format = info.format; + return EGL_NATIVES_FLAG_SIZE_CHANGED; + } + return 0; +} + +uint32_t EGLNativeWindowSurface::nextBuffer() +{ + const sp<Surface>& surface(mSurface); + Surface::SurfaceInfo info; + surface->nextBuffer(&info); + // update the address of the buffer to draw to next + egl_native_window_t::base = intptr_t(info.base); + egl_native_window_t::offset = intptr_t(info.bits) - intptr_t(info.base); + return 0; +} + +void EGLNativeWindowSurface::connect() +{ + if (!mConnected) { + Surface::SurfaceInfo info; + mSurface->lock(&info); + mSurface->setSwapRectangle(Rect(info.w, info.h)); + mConnected = true; + + egl_native_window_t::width = info.w; + egl_native_window_t::height = info.h; + egl_native_window_t::stride = info.bpr / bytesPerPixel(info.format); + egl_native_window_t::format = info.format; + egl_native_window_t::base = intptr_t(info.base); + egl_native_window_t::offset = intptr_t(info.bits) - intptr_t(info.base); + egl_native_window_t::memory_type = mSurface->getMemoryType(); + egl_native_window_t::fd = 0; + } +} + +void EGLNativeWindowSurface::disconnect() +{ + if (mConnected) { + mSurface->unlock(); + mConnected = false; + } +} + +// ---------------------------------------------------------------------------- +}; // namespace android +// ---------------------------------------------------------------------------- diff --git a/libs/ui/EventHub.cpp b/libs/ui/EventHub.cpp new file mode 100644 index 0000000..f0c77ba --- /dev/null +++ b/libs/ui/EventHub.cpp @@ -0,0 +1,743 @@ +// +// Copyright 2005 The Android Open Source Project +// +// Handle events, like key input and vsync. +// +// The goal is to provide an optimized solution for Linux, not an +// implementation that works well across all platforms. We expect +// events to arrive on file descriptors, so that we can use a select() +// select() call to sleep. +// +// We can't select() on anything but network sockets in Windows, so we +// provide an alternative implementation of waitEvent for that platform. +// +#define LOG_TAG "EventHub" + +//#define LOG_NDEBUG 0 + +#include <ui/EventHub.h> +#include <hardware/power.h> + +#include <cutils/properties.h> +#include <utils/IServiceManager.h> +#include <utils/Log.h> +#include <utils/Timers.h> +#include <utils.h> + +#include <stdlib.h> +#include <stdio.h> +#include <unistd.h> +#include <fcntl.h> +#include <memory.h> +#include <errno.h> +#include <assert.h> + +#include "KeyLayoutMap.h" + +#include <string.h> +#include <stdint.h> +#include <dirent.h> +#ifdef HAVE_INOTIFY +# include <sys/inotify.h> +#endif +#ifdef HAVE_ANDROID_OS +# include <sys/limits.h> /* not part of Linux */ +#endif +#include <sys/poll.h> +#include <sys/ioctl.h> + +/* this macro is used to tell if "bit" is set in "array" + * it selects a byte from the array, and does a boolean AND + * operation with a byte that only has the relevant bit set. + * eg. to check for the 12th bit, we do (array[1] & 1<<4) + */ +#define test_bit(bit, array) (array[bit/8] & (1<<(bit%8))) + +#define ID_MASK 0x0000ffff +#define SEQ_MASK 0x7fff0000 +#define SEQ_SHIFT 16 +#define id_to_index(id) ((id&ID_MASK)+1) + +namespace android { + +static const char *WAKE_LOCK_ID = "KeyEvents"; +static const char *device_path = "/dev/input"; + +/* return the larger integer */ +static inline int max(int v1, int v2) +{ + return (v1 > v2) ? v1 : v2; +} + +EventHub::device_t::device_t(int32_t _id, const char* _path) + : id(_id), path(_path), classes(0) + , layoutMap(new KeyLayoutMap()), next(NULL) { +} + +EventHub::device_t::~device_t() { + delete layoutMap; +} + +EventHub::EventHub(void) + : mError(NO_INIT), mHaveFirstKeyboard(false), mFirstKeyboardId(0) + , mDevicesById(0), mNumDevicesById(0) + , mOpeningDevices(0), mClosingDevices(0) + , mDevices(0), mFDs(0), mFDCount(0) +{ + acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_ID); +#ifdef EV_SW + memset(mSwitches, 0, sizeof(mSwitches)); +#endif +} + +/* + * Clean up. + */ +EventHub::~EventHub(void) +{ + release_wake_lock(WAKE_LOCK_ID); + // we should free stuff here... +} + +void EventHub::onFirstRef() +{ + mError = openPlatformInput() ? NO_ERROR : UNKNOWN_ERROR; +} + +status_t EventHub::errorCheck() const +{ + return mError; +} + +String8 EventHub::getDeviceName(int32_t deviceId) const +{ + AutoMutex _l(mLock); + device_t* device = getDevice(deviceId); + if (device == NULL) return String8(); + return device->name; +} + +uint32_t EventHub::getDeviceClasses(int32_t deviceId) const +{ + AutoMutex _l(mLock); + device_t* device = getDevice(deviceId); + if (device == NULL) return 0; + return device->classes; +} + +int EventHub::getAbsoluteInfo(int32_t deviceId, int axis, int *outMinValue, + int* outMaxValue, int* outFlat, int* outFuzz) const +{ + AutoMutex _l(mLock); + device_t* device = getDevice(deviceId); + if (device == NULL) return -1; + + struct input_absinfo info; + + if(ioctl(mFDs[id_to_index(device->id)].fd, EVIOCGABS(axis), &info)) { + LOGE("Error reading absolute controller %d for device %s fd %d\n", + axis, device->name.string(), mFDs[id_to_index(device->id)].fd); + return -1; + } + *outMinValue = info.minimum; + *outMaxValue = info.maximum; + *outFlat = info.flat; + *outFuzz = info.fuzz; + return 0; +} + +int EventHub::getSwitchState(int sw) const +{ +#ifdef EV_SW + if (sw >= 0 && sw <= SW_MAX) { + int32_t devid = mSwitches[sw]; + if (devid != 0) { + return getSwitchState(devid, sw); + } + } +#endif + return -1; +} + +int EventHub::getSwitchState(int32_t deviceId, int sw) const +{ +#ifdef EV_SW + AutoMutex _l(mLock); + device_t* device = getDevice(deviceId); + if (device == NULL) return -1; + + if (sw >= 0 && sw <= SW_MAX) { + uint8_t sw_bitmask[(SW_MAX+1)/8]; + memset(sw_bitmask, 0, sizeof(sw_bitmask)); + if (ioctl(mFDs[id_to_index(device->id)].fd, + EVIOCGSW(sizeof(sw_bitmask)), sw_bitmask) >= 0) { + return test_bit(sw, sw_bitmask) ? 1 : 0; + } + } +#endif + + return -1; +} + +int EventHub::getScancodeState(int code) const +{ + return getScancodeState(mFirstKeyboardId, code); +} + +int EventHub::getScancodeState(int32_t deviceId, int code) const +{ + AutoMutex _l(mLock); + device_t* device = getDevice(deviceId); + if (device == NULL) return -1; + + if (code >= 0 && code <= KEY_MAX) { + uint8_t key_bitmask[(KEY_MAX+1)/8]; + memset(key_bitmask, 0, sizeof(key_bitmask)); + if (ioctl(mFDs[id_to_index(device->id)].fd, + EVIOCGKEY(sizeof(key_bitmask)), key_bitmask) >= 0) { + return test_bit(code, key_bitmask) ? 1 : 0; + } + } + + return -1; +} + +int EventHub::getKeycodeState(int code) const +{ + return getKeycodeState(mFirstKeyboardId, code); +} + +int EventHub::getKeycodeState(int32_t deviceId, int code) const +{ + AutoMutex _l(mLock); + device_t* device = getDevice(deviceId); + if (device == NULL || device->layoutMap == NULL) return -1; + + Vector<int32_t> scanCodes; + device->layoutMap->findScancodes(code, &scanCodes); + + uint8_t key_bitmask[(KEY_MAX+1)/8]; + memset(key_bitmask, 0, sizeof(key_bitmask)); + if (ioctl(mFDs[id_to_index(device->id)].fd, + EVIOCGKEY(sizeof(key_bitmask)), key_bitmask) >= 0) { + #if 0 + for (size_t i=0; i<=KEY_MAX; i++) { + LOGI("(Scan code %d: down=%d)", i, test_bit(i, key_bitmask)); + } + #endif + const size_t N = scanCodes.size(); + for (size_t i=0; i<N && i<=KEY_MAX; i++) { + int32_t sc = scanCodes.itemAt(i); + //LOGI("Code %d: down=%d", sc, test_bit(sc, key_bitmask)); + if (sc >= 0 && sc <= KEY_MAX && test_bit(sc, key_bitmask)) { + return 1; + } + } + } + + return 0; +} + +EventHub::device_t* EventHub::getDevice(int32_t deviceId) const +{ + if (deviceId == 0) deviceId = mFirstKeyboardId; + int32_t id = deviceId & ID_MASK; + if (id >= mNumDevicesById || id < 0) return NULL; + device_t* dev = mDevicesById[id].device; + if (dev->id == deviceId) { + return dev; + } + return NULL; +} + +bool EventHub::getEvent(int32_t* outDeviceId, int32_t* outType, + int32_t* outScancode, int32_t* outKeycode, uint32_t *outFlags, + int32_t* outValue, nsecs_t* outWhen) +{ + *outDeviceId = 0; + *outType = 0; + *outScancode = 0; + *outKeycode = 0; + *outFlags = 0; + *outValue = 0; + *outWhen = 0; + + status_t err; + + fd_set readfds; + int maxFd = -1; + int cc; + int i; + int res; + int pollres; + struct input_event iev; + + // Note that we only allow one caller to getEvent(), so don't need + // to do locking here... only when adding/removing devices. + + while(1) { + + // First, report any devices that had last been added/removed. + if (mClosingDevices != NULL) { + device_t* device = mClosingDevices; + LOGV("Reporting device closed: id=0x%x, name=%s\n", + device->id, device->path.string()); + mClosingDevices = device->next; + *outDeviceId = device->id; + if (*outDeviceId == mFirstKeyboardId) *outDeviceId = 0; + *outType = DEVICE_REMOVED; + delete device; + return true; + } + if (mOpeningDevices != NULL) { + device_t* device = mOpeningDevices; + LOGV("Reporting device opened: id=0x%x, name=%s\n", + device->id, device->path.string()); + mOpeningDevices = device->next; + *outDeviceId = device->id; + if (*outDeviceId == mFirstKeyboardId) *outDeviceId = 0; + *outType = DEVICE_ADDED; + return true; + } + + release_wake_lock(WAKE_LOCK_ID); + + pollres = poll(mFDs, mFDCount, -1); + + acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_ID); + + if (pollres <= 0) { + if (errno != EINTR) { + LOGW("select failed (errno=%d)\n", errno); + usleep(100000); + } + continue; + } + + //printf("poll %d, returned %d\n", mFDCount, pollres); + if(mFDs[0].revents & POLLIN) { + read_notify(mFDs[0].fd); + } + for(i = 1; i < mFDCount; i++) { + if(mFDs[i].revents) { + LOGV("revents for %d = 0x%08x", i, mFDs[i].revents); + if(mFDs[i].revents & POLLIN) { + res = read(mFDs[i].fd, &iev, sizeof(iev)); + if (res == sizeof(iev)) { + LOGV("%s got: t0=%d, t1=%d, type=%d, code=%d, v=%d", + mDevices[i]->path.string(), + (int) iev.time.tv_sec, (int) iev.time.tv_usec, + iev.type, iev.code, iev.value); + *outDeviceId = mDevices[i]->id; + if (*outDeviceId == mFirstKeyboardId) *outDeviceId = 0; + *outType = iev.type; + *outScancode = iev.code; + if (iev.type == EV_KEY) { + err = mDevices[i]->layoutMap->map(iev.code, outKeycode, outFlags); + LOGV("iev.code=%d outKeycode=%d outFlags=0x%08x err=%d\n", + iev.code, *outKeycode, *outFlags, err); + if (err != 0) { + *outKeycode = 0; + *outFlags = 0; + } + } else { + *outKeycode = iev.code; + } + *outValue = iev.value; + *outWhen = s2ns(iev.time.tv_sec) + us2ns(iev.time.tv_usec); + return true; + } else { + if (res<0) { + LOGW("could not get event (errno=%d)", errno); + } else { + LOGE("could not get event (wrong size: %d)", res); + } + continue; + } + } + } + } + } +} + +/* + * Open the platform-specific input device. + */ +bool EventHub::openPlatformInput(void) +{ + /* + * Open platform-specific input device(s). + */ + int res; + + mFDCount = 1; + mFDs = (pollfd *)calloc(1, sizeof(mFDs[0])); + mDevices = (device_t **)calloc(1, sizeof(mDevices[0])); + mFDs[0].events = POLLIN; + mDevices[0] = NULL; +#ifdef HAVE_INOTIFY + mFDs[0].fd = inotify_init(); + res = inotify_add_watch(mFDs[0].fd, device_path, IN_DELETE | IN_CREATE); + if(res < 0) { + LOGE("could not add watch for %s, %s\n", device_path, strerror(errno)); + } +#else + /* + * The code in EventHub::getEvent assumes that mFDs[0] is an inotify fd. + * We allocate space for it and set it to something invalid. + */ + mFDs[0].fd = -1; +#endif + + res = scan_dir(device_path); + if(res < 0) { + LOGE("scan dir failed for %s\n", device_path); + //open_device("/dev/input/event0"); + } + + return true; +} + +// ---------------------------------------------------------------------------- + +int EventHub::open_device(const char *deviceName) +{ + int version; + int fd; + struct pollfd *new_mFDs; + device_t **new_devices; + char **new_device_names; + char name[80]; + char location[80]; + char idstr[80]; + struct input_id id; + + LOGV("Opening device: %s", deviceName); + + AutoMutex _l(mLock); + + fd = open(deviceName, O_RDWR); + if(fd < 0) { + LOGE("could not open %s, %s\n", deviceName, strerror(errno)); + return -1; + } + + if(ioctl(fd, EVIOCGVERSION, &version)) { + LOGE("could not get driver version for %s, %s\n", deviceName, strerror(errno)); + return -1; + } + if(ioctl(fd, EVIOCGID, &id)) { + LOGE("could not get driver id for %s, %s\n", deviceName, strerror(errno)); + return -1; + } + name[sizeof(name) - 1] = '\0'; + location[sizeof(location) - 1] = '\0'; + idstr[sizeof(idstr) - 1] = '\0'; + if(ioctl(fd, EVIOCGNAME(sizeof(name) - 1), &name) < 1) { + //fprintf(stderr, "could not get device name for %s, %s\n", deviceName, strerror(errno)); + name[0] = '\0'; + } + if(ioctl(fd, EVIOCGPHYS(sizeof(location) - 1), &location) < 1) { + //fprintf(stderr, "could not get location for %s, %s\n", deviceName, strerror(errno)); + location[0] = '\0'; + } + if(ioctl(fd, EVIOCGUNIQ(sizeof(idstr) - 1), &idstr) < 1) { + //fprintf(stderr, "could not get idstring for %s, %s\n", deviceName, strerror(errno)); + idstr[0] = '\0'; + } + + int devid = 0; + while (devid < mNumDevicesById) { + if (mDevicesById[devid].device == NULL) { + break; + } + devid++; + } + if (devid >= mNumDevicesById) { + device_ent* new_devids = (device_ent*)realloc(mDevicesById, + sizeof(mDevicesById[0]) * (devid + 1)); + if (new_devids == NULL) { + LOGE("out of memory"); + return -1; + } + mDevicesById = new_devids; + mNumDevicesById = devid+1; + mDevicesById[devid].device = NULL; + mDevicesById[devid].seq = 0; + } + + mDevicesById[devid].seq = (mDevicesById[devid].seq+(1<<SEQ_SHIFT))&SEQ_MASK; + if (mDevicesById[devid].seq == 0) { + mDevicesById[devid].seq = 1<<SEQ_SHIFT; + } + + new_mFDs = (pollfd*)realloc(mFDs, sizeof(mFDs[0]) * (mFDCount + 1)); + new_devices = (device_t**)realloc(mDevices, sizeof(mDevices[0]) * (mFDCount + 1)); + if (new_mFDs == NULL || new_devices == NULL) { + LOGE("out of memory"); + return -1; + } + mFDs = new_mFDs; + mDevices = new_devices; + +#if 0 + LOGI("add device %d: %s\n", mFDCount, deviceName); + LOGI(" bus: %04x\n" + " vendor %04x\n" + " product %04x\n" + " version %04x\n", + id.bustype, id.vendor, id.product, id.version); + LOGI(" name: \"%s\"\n", name); + LOGI(" location: \"%s\"\n" + " id: \"%s\"\n", location, idstr); + LOGI(" version: %d.%d.%d\n", + version >> 16, (version >> 8) & 0xff, version & 0xff); +#endif + + device_t* device = new device_t(devid|mDevicesById[devid].seq, deviceName); + if (device == NULL) { + LOGE("out of memory"); + return -1; + } + + mFDs[mFDCount].fd = fd; + mFDs[mFDCount].events = POLLIN; + + // figure out the kinds of events the device reports + uint8_t key_bitmask[(KEY_MAX+1)/8]; + memset(key_bitmask, 0, sizeof(key_bitmask)); + LOGV("Getting keys..."); + if (ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(key_bitmask)), key_bitmask) >= 0) { + //LOGI("MAP\n"); + //for (int i=0; i<((KEY_MAX+1)/8); i++) { + // LOGI("%d: 0x%02x\n", i, key_bitmask[i]); + //} + for (int i=0; i<((BTN_MISC+7)/8); i++) { + if (key_bitmask[i] != 0) { + device->classes |= CLASS_KEYBOARD; + break; + } + } + } + if (test_bit(BTN_MOUSE, key_bitmask)) { + uint8_t rel_bitmask[(REL_MAX+1)/8]; + memset(rel_bitmask, 0, sizeof(rel_bitmask)); + LOGV("Getting relative controllers..."); + if (ioctl(fd, EVIOCGBIT(EV_REL, sizeof(rel_bitmask)), rel_bitmask) >= 0) + { + if (test_bit(REL_X, rel_bitmask) && test_bit(REL_Y, rel_bitmask)) { + device->classes |= CLASS_TRACKBALL; + } + } + } + if (test_bit(BTN_TOUCH, key_bitmask)) { + uint8_t abs_bitmask[(ABS_MAX+1)/8]; + memset(abs_bitmask, 0, sizeof(abs_bitmask)); + LOGV("Getting absolute controllers..."); + if (ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(abs_bitmask)), abs_bitmask) >= 0) + { + if (test_bit(ABS_X, abs_bitmask) && test_bit(ABS_Y, abs_bitmask)) { + device->classes |= CLASS_TOUCHSCREEN; + } + } + } + +#ifdef EV_SW + // figure out the switches this device reports + uint8_t sw_bitmask[(SW_MAX+1)/8]; + memset(sw_bitmask, 0, sizeof(sw_bitmask)); + if (ioctl(fd, EVIOCGBIT(EV_SW, sizeof(sw_bitmask)), sw_bitmask) >= 0) { + for (int i=0; i<EV_SW; i++) { + //LOGI("Device 0x%x sw %d: has=%d", device->id, i, test_bit(i, sw_bitmask)); + if (test_bit(i, sw_bitmask)) { + if (mSwitches[i] == 0) { + mSwitches[i] = device->id; + } + } + } + } +#endif + + LOGI("New device: path=%s name=%s id=0x%x (of 0x%x) index=%d fd=%d classes=0x%x\n", + deviceName, name, device->id, mNumDevicesById, mFDCount, fd, device->classes); + + if ((device->classes&CLASS_KEYBOARD) != 0) { + char devname[101]; + char tmpfn[101]; + char keylayoutFilename[300]; + + // a more descriptive name + ioctl(mFDs[mFDCount].fd, EVIOCGNAME(sizeof(devname)-1), devname); + devname[sizeof(devname)-1] = 0; + device->name = devname; + + // replace all the spaces with underscores + strcpy(tmpfn, devname); + for (char *p = strchr(tmpfn, ' '); p && *p; p = strchr(tmpfn, ' ')) + *p = '_'; + + // find the .kl file we need for this device + const char* root = getenv("ANDROID_ROOT"); + snprintf(keylayoutFilename, sizeof(keylayoutFilename), + "%s/usr/keylayout/%s.kl", root, tmpfn); + bool defaultKeymap = false; + if (access(keylayoutFilename, R_OK)) { + snprintf(keylayoutFilename, sizeof(keylayoutFilename), + "%s/usr/keylayout/%s", root, "qwerty.kl"); + defaultKeymap = true; + } + device->layoutMap->load(keylayoutFilename); + + // tell the world about the devname (the descriptive name) + int32_t publicID; + if (!mHaveFirstKeyboard && !defaultKeymap) { + publicID = 0; + // the built-in keyboard has a well-known device ID of 0, + // this device better not go away. + mHaveFirstKeyboard = true; + mFirstKeyboardId = device->id; + } else { + publicID = device->id; + // ensure mFirstKeyboardId is set to -something-. + if (mFirstKeyboardId == 0) { + mFirstKeyboardId = device->id; + } + } + char propName[100]; + sprintf(propName, "hw.keyboards.%u.devname", publicID); + property_set(propName, devname); + + LOGI("New keyboard: publicID=%d device->id=%d devname='%s propName='%s' keylayout='%s'\n", + publicID, device->id, devname, propName, keylayoutFilename); + } + + LOGV("Adding device %s %p at %d, id = %d, classes = 0x%x\n", + deviceName, device, mFDCount, devid, device->classes); + + mDevicesById[devid].device = device; + device->next = mOpeningDevices; + mOpeningDevices = device; + mDevices[mFDCount] = device; + + mFDCount++; + return 0; +} + +int EventHub::close_device(const char *deviceName) +{ + AutoMutex _l(mLock); + + int i; + for(i = 1; i < mFDCount; i++) { + if(strcmp(mDevices[i]->path.string(), deviceName) == 0) { + //LOGD("remove device %d: %s\n", i, deviceName); + device_t* device = mDevices[i]; + int count = mFDCount - i - 1; + int index = (device->id&ID_MASK); + mDevicesById[index].device = NULL; + memmove(mDevices + i, mDevices + i + 1, sizeof(mDevices[0]) * count); + memmove(mFDs + i, mFDs + i + 1, sizeof(mFDs[0]) * count); + +#ifdef EV_SW + for (int j=0; j<EV_SW; j++) { + if (mSwitches[j] == device->id) { + mSwitches[j] = 0; + } + } +#endif + + device->next = mClosingDevices; + mClosingDevices = device; + + mFDCount--; + + uint32_t publicID; + if (device->id == mFirstKeyboardId) { + LOGW("built-in keyboard device %s (id=%d) is closing! the apps will not like this", + device->path.string(), mFirstKeyboardId); + mFirstKeyboardId = 0; + publicID = 0; + } else { + publicID = device->id; + } + // clear the property + char propName[100]; + sprintf(propName, "hw.keyboards.%u.devname", publicID); + property_set(propName, NULL); + return 0; + } + } + LOGE("remote device: %s not found\n", deviceName); + return -1; +} + +int EventHub::read_notify(int nfd) +{ +#ifdef HAVE_INOTIFY + int res; + char devname[PATH_MAX]; + char *filename; + char event_buf[512]; + int event_size; + int event_pos = 0; + struct inotify_event *event; + + res = read(nfd, event_buf, sizeof(event_buf)); + if(res < (int)sizeof(*event)) { + if(errno == EINTR) + return 0; + LOGW("could not get event, %s\n", strerror(errno)); + return 1; + } + //printf("got %d bytes of event information\n", res); + + strcpy(devname, device_path); + filename = devname + strlen(devname); + *filename++ = '/'; + + while(res >= (int)sizeof(*event)) { + event = (struct inotify_event *)(event_buf + event_pos); + //printf("%d: %08x \"%s\"\n", event->wd, event->mask, event->len ? event->name : ""); + if(event->len) { + strcpy(filename, event->name); + if(event->mask & IN_CREATE) { + open_device(devname); + } + else { + close_device(devname); + } + } + event_size = sizeof(*event) + event->len; + res -= event_size; + event_pos += event_size; + } +#endif + return 0; +} + + +int EventHub::scan_dir(const char *dirname) +{ + char devname[PATH_MAX]; + char *filename; + DIR *dir; + struct dirent *de; + dir = opendir(dirname); + if(dir == NULL) + return -1; + strcpy(devname, dirname); + filename = devname + strlen(devname); + *filename++ = '/'; + while((de = readdir(dir))) { + if(de->d_name[0] == '.' && + (de->d_name[1] == '\0' || + (de->d_name[1] == '.' && de->d_name[2] == '\0'))) + continue; + strcpy(filename, de->d_name); + open_device(devname); + } + closedir(dir); + return 0; +} + +}; // namespace android diff --git a/libs/ui/EventRecurrence.cpp b/libs/ui/EventRecurrence.cpp new file mode 100644 index 0000000..b436b50 --- /dev/null +++ b/libs/ui/EventRecurrence.cpp @@ -0,0 +1,484 @@ +/* + * Copyright 2006 The Android Open Source Project + */ + +#include <pim/EventRecurrence.h> +#include <utils/String8.h> +#include <stdio.h> +#include <limits.h> + +namespace android { + +#define FAIL_HERE() do { \ + printf("Parsing failed at line %d\n", __LINE__); \ + return UNKNOWN_ERROR; \ + } while(0) + +EventRecurrence::EventRecurrence() + :freq((freq_t)0), + until(), + count(0), + interval(0), + bysecond(0), + bysecondCount(0), + byminute(0), + byminuteCount(0), + byhour(0), + byhourCount(0), + byday(0), + bydayNum(0), + bydayCount(0), + bymonthday(0), + bymonthdayCount(0), + byyearday(0), + byyeardayCount(0), + byweekno(0), + byweeknoCount(0), + bymonth(0), + bymonthCount(0), + bysetpos(0), + bysetposCount(0), + wkst(0) +{ +} + +EventRecurrence::~EventRecurrence() +{ + delete[] bysecond; + delete[] byminute; + delete[] byhour; + delete[] byday; + delete[] bydayNum; + delete[] byyearday; + delete[] bymonthday; + delete[] byweekno; + delete[] bymonth; + delete[] bysetpos; +} + +enum LHS { + NONE_LHS = 0, + FREQ, + UNTIL, + COUNT, + INTERVAL, + BYSECOND, + BYMINUTE, + BYHOUR, + BYDAY, + BYMONTHDAY, + BYYEARDAY, + BYWEEKNO, + BYMONTH, + BYSETPOS, + WKST +}; + +struct LHSProc +{ + const char16_t* text; + size_t textSize; + uint32_t value; +}; + +const char16_t FREQ_text[] = { 'F', 'R', 'E', 'Q' }; +const char16_t UNTIL_text[] = { 'U', 'N', 'T', 'I', 'L' }; +const char16_t COUNT_text[] = { 'C', 'O', 'U', 'N', 'T' }; +const char16_t INTERVAL_text[] = { 'I', 'N', 'T', 'E', 'R', 'V', 'A', 'L'}; +const char16_t BYSECOND_text[] = { 'B', 'Y', 'S', 'E', 'C', 'O', 'N', 'D' }; +const char16_t BYMINUTE_text[] = { 'B', 'Y', 'M', 'I', 'N', 'U', 'T', 'E' }; +const char16_t BYHOUR_text[] = { 'B', 'Y', 'H', 'O', 'U', 'R' }; +const char16_t BYDAY_text[] = { 'B', 'Y', 'D', 'A', 'Y' }; +const char16_t BYMONTHDAY_text[] = { 'B','Y','M','O','N','T','H','D','A','Y' }; +const char16_t BYYEARDAY_text[] = { 'B','Y','Y','E','A','R','D','A','Y' }; +const char16_t BYWEEKNO_text[] = { 'B', 'Y', 'W', 'E', 'E', 'K', 'N', 'O' }; +const char16_t BYMONTH_text[] = { 'B', 'Y', 'M', 'O', 'N', 'T', 'H' }; +const char16_t BYSETPOS_text[] = { 'B', 'Y', 'S', 'E', 'T', 'P', 'O', 'S' }; +const char16_t WKST_text[] = { 'W', 'K', 'S', 'T' }; + +#define SIZ(x) (sizeof(x)/sizeof(x[0])) + +const LHSProc LHSPROC[] = { + { FREQ_text, SIZ(FREQ_text), FREQ }, + { UNTIL_text, SIZ(UNTIL_text), UNTIL }, + { COUNT_text, SIZ(COUNT_text), COUNT }, + { INTERVAL_text, SIZ(INTERVAL_text), INTERVAL }, + { BYSECOND_text, SIZ(BYSECOND_text), BYSECOND }, + { BYMINUTE_text, SIZ(BYMINUTE_text), BYMINUTE }, + { BYHOUR_text, SIZ(BYHOUR_text), BYHOUR }, + { BYDAY_text, SIZ(BYDAY_text), BYDAY }, + { BYMONTHDAY_text, SIZ(BYMONTHDAY_text), BYMONTHDAY }, + { BYYEARDAY_text, SIZ(BYYEARDAY_text), BYYEARDAY }, + { BYWEEKNO_text, SIZ(BYWEEKNO_text), BYWEEKNO }, + { BYMONTH_text, SIZ(BYMONTH_text), BYMONTH }, + { BYSETPOS_text, SIZ(BYSETPOS_text), BYSETPOS }, + { WKST_text, SIZ(WKST_text), WKST }, + { NULL, 0, NONE_LHS }, +}; + +const char16_t SECONDLY_text[] = { 'S','E','C','O','N','D','L','Y' }; +const char16_t MINUTELY_text[] = { 'M','I','N','U','T','E','L','Y' }; +const char16_t HOURLY_text[] = { 'H','O','U','R','L','Y' }; +const char16_t DAILY_text[] = { 'D','A','I','L','Y' }; +const char16_t WEEKLY_text[] = { 'W','E','E','K','L','Y' }; +const char16_t MONTHLY_text[] = { 'M','O','N','T','H','L','Y' }; +const char16_t YEARLY_text[] = { 'Y','E','A','R','L','Y' }; + +typedef LHSProc FreqProc; + +const FreqProc FREQPROC[] = { + { SECONDLY_text, SIZ(SECONDLY_text), EventRecurrence::SECONDLY }, + { MINUTELY_text, SIZ(MINUTELY_text), EventRecurrence::MINUTELY }, + { HOURLY_text, SIZ(HOURLY_text), EventRecurrence::HOURLY }, + { DAILY_text, SIZ(DAILY_text), EventRecurrence::DAILY }, + { WEEKLY_text, SIZ(WEEKLY_text), EventRecurrence::WEEKLY }, + { MONTHLY_text, SIZ(MONTHLY_text), EventRecurrence::MONTHLY }, + { YEARLY_text, SIZ(YEARLY_text), EventRecurrence::YEARLY }, + { NULL, 0, NONE_LHS }, +}; + +const char16_t SU_text[] = { 'S','U' }; +const char16_t MO_text[] = { 'M','O' }; +const char16_t TU_text[] = { 'T','U' }; +const char16_t WE_text[] = { 'W','E' }; +const char16_t TH_text[] = { 'T','H' }; +const char16_t FR_text[] = { 'F','R' }; +const char16_t SA_text[] = { 'S','A' }; + +const FreqProc WEEKDAYPROC[] = { + { SU_text, SIZ(SU_text), EventRecurrence::SU }, + { MO_text, SIZ(MO_text), EventRecurrence::MO }, + { TU_text, SIZ(TU_text), EventRecurrence::TU }, + { WE_text, SIZ(WE_text), EventRecurrence::WE }, + { TH_text, SIZ(TH_text), EventRecurrence::TH }, + { FR_text, SIZ(FR_text), EventRecurrence::FR }, + { SA_text, SIZ(SA_text), EventRecurrence::SA }, + { NULL, 0, NONE_LHS }, +}; + +// returns the index into LHSPROC for the match or -1 if not found +inline static int +match_proc(const LHSProc* p, const char16_t* str, size_t len) +{ + int i = 0; + while (p->text != NULL) { + if (p->textSize == len) { + if (0 == memcmp(p->text, str, len*sizeof(char16_t))) { + return i; + } + } + p++; + i++; + } + return -1; +} + +// rangeMin and rangeMax are inclusive +static status_t +parse_int(const char16_t* str, size_t len, int* out, + int rangeMin, int rangeMax, bool zeroOK) +{ + char16_t c; + size_t i=0; + + if (len == 0) { + FAIL_HERE(); + } + bool negative = false; + c = str[0]; + if (c == '-' ) { + negative = true; + i++; + } + else if (c == '+') { + i++; + } + int n = 0; + for (; i<len; i++) { + c = str[i]; + if (c < '0' || c > '9') { + FAIL_HERE(); + } + int prev = n; + n *= 10; + // the spec doesn't address how big these numbers can be, + // so we're not going to worry about not being able to represent + // INT_MIN, and if we're going to wrap, we'll just clamp to + // INT_MAX instead + if (n < prev) { + n = INT_MAX; + } else { + n += c - '0'; + } + } + if (negative) { + n = -n; + } + if (n < rangeMin || n > rangeMax) { + FAIL_HERE(); + } + if (!zeroOK && n == 0) { + FAIL_HERE(); + } + *out = n; + return NO_ERROR; +} + +static status_t +parse_int_list(const char16_t* str, size_t len, int* countOut, int** listOut, + int rangeMin, int rangeMax, bool zeroOK, + status_t (*func)(const char16_t*,size_t,int*,int,int,bool)=parse_int) +{ + status_t err; + + if (len == 0) { + *countOut = 0; + *listOut = NULL; + return NO_ERROR; + } + + // make one pass through looking for commas so we know how big to make our + // out array. + int count = 1; + for (size_t i=0; i<len; i++) { + if (str[i] == ',') { + count++; + } + } + + int* list = new int[count]; + const char16_t* p = str; + int commaIndex = 0; + size_t i; + + for (i=0; i<len; i++) { + if (str[i] == ',') { + err = func(p, (str+i-p), list+commaIndex, rangeMin, + rangeMax, zeroOK); + if (err != NO_ERROR) { + goto bail; + } + commaIndex++; + p = str+i+1; + } + } + + err = func(p, (str+i-p), list+commaIndex, rangeMin, rangeMax, zeroOK); + if (err != NO_ERROR) { + goto bail; + } + commaIndex++; + + *countOut = count; + *listOut = list; + + return NO_ERROR; + +bail: + delete[] list; + FAIL_HERE(); +} + +// the numbers here are small, so we pack them both into one value, and then +// split it out later. it lets us reuse all the comma separated list code. +static status_t +parse_byday(const char16_t* s, size_t len, int* out, + int rangeMin, int rangeMax, bool zeroOK) +{ + status_t err; + int n = 0; + const char16_t* p = s; + size_t plen = len; + + if (len > 0) { + char16_t c = s[0]; + if (c == '-' || c == '+' || (c >= '0' && c <= '9')) { + if (len > 1) { + size_t nlen = 0; + c = s[nlen]; + while (nlen < len + && (c == '-' || c == '+' || (c >= '0' && c <= '9'))) { + c = s[nlen]; + nlen++; + } + if (nlen > 0) { + nlen--; + err = parse_int(s, nlen, &n, rangeMin, rangeMax, zeroOK); + if (err != NO_ERROR) { + FAIL_HERE(); + } + p += nlen; + plen -= nlen; + } + } + } + + int index = match_proc(WEEKDAYPROC, p, plen); + if (index >= 0) { + *out = (0xffff0000 & WEEKDAYPROC[index].value) + | (0x0000ffff & n); + return NO_ERROR; + } + } + return UNKNOWN_ERROR; +} + +static void +postprocess_byday(int count, int* byday, int** bydayNum) +{ + int* bdn = new int[count]; + *bydayNum = bdn; + for (int i=0; i<count; i++) { + uint32_t v = byday[i]; + int16_t num = v & 0x0000ffff; + byday[i] = v & 0xffff0000; + // will sign extend: + bdn[i] = num; + } +} + +#define PARSE_INT_LIST_CHECKED(name, rangeMin, rangeMax, zeroOK) \ + if (name##Count != 0 || NO_ERROR != parse_int_list(s, slen, \ + &name##Count, &name, rangeMin, rangeMax, zeroOK)) { \ + FAIL_HERE(); \ + } +status_t +EventRecurrence::parse(const String16& str) +{ + char16_t const* work = str.string(); + size_t len = str.size(); + + int lhsIndex = NONE_LHS; + int index; + + size_t start = 0; + for (size_t i=0; i<len; i++) { + char16_t c = work[i]; + if (c != ';' && i == len-1) { + c = ';'; + i++; + } + if (c == ';' || c == '=') { + if (i != start) { + const char16_t* s = work+start; + const size_t slen = i-start; + + String8 thestring(String16(s, slen)); + + switch (c) + { + case '=': + if (lhsIndex == NONE_LHS) { + lhsIndex = match_proc(LHSPROC, s, slen); + if (lhsIndex >= 0) { + break; + } + } + FAIL_HERE(); + case ';': + { + switch (LHSPROC[lhsIndex].value) + { + case FREQ: + if (this->freq != 0) { + FAIL_HERE(); + } + index = match_proc(FREQPROC, s, slen); + if (index >= 0) { + this->freq = (freq_t)FREQPROC[index].value; + } + break; + case UNTIL: + // XXX should check that this is a valid time + until.setTo(String16(s, slen)); + break; + case COUNT: + if (count != 0 + || NO_ERROR != parse_int(s, slen, + &count, INT_MIN, INT_MAX, true)) { + FAIL_HERE(); + } + break; + case INTERVAL: + if (interval != 0 + || NO_ERROR != parse_int(s, slen, + &interval, INT_MIN, INT_MAX, false)) { + FAIL_HERE(); + } + break; + case BYSECOND: + PARSE_INT_LIST_CHECKED(bysecond, 0, 59, true) + break; + case BYMINUTE: + PARSE_INT_LIST_CHECKED(byminute, 0, 59, true) + break; + case BYHOUR: + PARSE_INT_LIST_CHECKED(byhour, 0, 23, true) + break; + case BYDAY: + if (bydayCount != 0 || NO_ERROR != + parse_int_list(s, slen, &bydayCount, + &byday, -53, 53, false, + parse_byday)) { + FAIL_HERE(); + } + postprocess_byday(bydayCount, byday, &bydayNum); + break; + case BYMONTHDAY: + PARSE_INT_LIST_CHECKED(bymonthday, -31, 31, + false) + break; + case BYYEARDAY: + PARSE_INT_LIST_CHECKED(byyearday, -366, 366, + false) + break; + case BYWEEKNO: + PARSE_INT_LIST_CHECKED(byweekno, -53, 53, + false) + break; + case BYMONTH: + PARSE_INT_LIST_CHECKED(bymonth, 1, 12, false) + break; + case BYSETPOS: + PARSE_INT_LIST_CHECKED(bysetpos, + INT_MIN, INT_MAX, true) + break; + case WKST: + if (this->wkst != 0) { + FAIL_HERE(); + } + index = match_proc(WEEKDAYPROC, s, slen); + if (index >= 0) { + this->wkst = (int)WEEKDAYPROC[index].value; + } + break; + default: + FAIL_HERE(); + } + lhsIndex = NONE_LHS; + break; + } + } + + start = i+1; + } + } + } + + // enforce that there was a FREQ + if (freq == 0) { + FAIL_HERE(); + } + + // default wkst to MO if it wasn't specified + if (wkst == 0) { + wkst = MO; + } + + return NO_ERROR; +} + + +}; // namespace android + + diff --git a/libs/ui/ICamera.cpp b/libs/ui/ICamera.cpp new file mode 100644 index 0000000..420bb49 --- /dev/null +++ b/libs/ui/ICamera.cpp @@ -0,0 +1,204 @@ +/* +** +** Copyright 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. +*/ + +#include <stdint.h> +#include <sys/types.h> + +#include <utils/Parcel.h> + +#include <ui/ICamera.h> + +#define LOG_TAG "@@@@@@@@@@@ CAMERA @@@@@@@@@@@" +#include <utils/Log.h> + +namespace android { + +enum { + DISCONNECT = IBinder::FIRST_CALL_TRANSACTION, + SET_PREVIEW_DISPLAY, + SET_HAS_FRAME_CALLBACK, + START_PREVIEW, + STOP_PREVIEW, + AUTO_FOCUS, + TAKE_PICTURE, + SET_PARAMETERS, + GET_PARAMETERS +}; + +class BpCamera: public BpInterface<ICamera> +{ +public: + BpCamera(const sp<IBinder>& impl) + : BpInterface<ICamera>(impl) + { + } + + // disconnect from camera service + void disconnect() + { + Parcel data, reply; + data.writeInterfaceToken(ICamera::getInterfaceDescriptor()); + remote()->transact(DISCONNECT, data, &reply); + } + + // pass the buffered ISurface to the camera service + status_t setPreviewDisplay(const sp<ISurface>& surface) + { + Parcel data, reply; + data.writeInterfaceToken(ICamera::getInterfaceDescriptor()); + data.writeStrongBinder(surface->asBinder()); + remote()->transact(SET_PREVIEW_DISPLAY, data, &reply); + return reply.readInt32(); + } + + // tell the service whether to callback with each preview frame + void setHasFrameCallback(bool installed) + { + Parcel data, reply; + data.writeInterfaceToken(ICamera::getInterfaceDescriptor()); + data.writeInt32((int32_t)installed); + remote()->transact(SET_HAS_FRAME_CALLBACK, data, &reply); + } + + // start preview mode, must call setPreviewDisplay first + status_t startPreview() + { + Parcel data, reply; + data.writeInterfaceToken(ICamera::getInterfaceDescriptor()); + remote()->transact(START_PREVIEW, data, &reply); + return reply.readInt32(); + } + + // stop preview mode + void stopPreview() + { + Parcel data, reply; + data.writeInterfaceToken(ICamera::getInterfaceDescriptor()); + remote()->transact(STOP_PREVIEW, data, &reply); + } + + // auto focus + status_t autoFocus() + { + Parcel data, reply; + data.writeInterfaceToken(ICamera::getInterfaceDescriptor()); + remote()->transact(AUTO_FOCUS, data, &reply); + status_t ret = reply.readInt32(); + return ret; + } + + // take a picture - returns an IMemory (ref-counted mmap) + status_t takePicture() + { + Parcel data, reply; + data.writeInterfaceToken(ICamera::getInterfaceDescriptor()); + remote()->transact(TAKE_PICTURE, data, &reply); + status_t ret = reply.readInt32(); + return ret; + } + + // set preview/capture parameters - key/value pairs + status_t setParameters(const String8& params) + { + Parcel data, reply; + data.writeInterfaceToken(ICamera::getInterfaceDescriptor()); + data.writeString8(params); + remote()->transact(SET_PARAMETERS, data, &reply); + return reply.readInt32(); + } + + // get preview/capture parameters - key/value pairs + String8 getParameters() const + { + Parcel data, reply; + data.writeInterfaceToken(ICamera::getInterfaceDescriptor()); + remote()->transact(GET_PARAMETERS, data, &reply); + return reply.readString8(); + } +}; + +IMPLEMENT_META_INTERFACE(Camera, "android.hardware.ICamera"); + +// ---------------------------------------------------------------------- + +#define CHECK_INTERFACE(interface, data, reply) \ + do { if (!data.enforceInterface(interface::getInterfaceDescriptor())) { \ + LOGW("Call incorrectly routed to " #interface); \ + return PERMISSION_DENIED; \ + } } while (0) + +status_t BnCamera::onTransact( + uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) +{ + switch(code) { + case DISCONNECT: { + CHECK_INTERFACE(ICamera, data, reply); + disconnect(); + return NO_ERROR; + } break; + case SET_PREVIEW_DISPLAY: { + CHECK_INTERFACE(ICamera, data, reply); + sp<ISurface> surface = interface_cast<ISurface>(data.readStrongBinder()); + reply->writeInt32(setPreviewDisplay(surface)); + return NO_ERROR; + } break; + case SET_HAS_FRAME_CALLBACK: { + CHECK_INTERFACE(ICamera, data, reply); + bool installed = (bool)data.readInt32(); + setHasFrameCallback(installed); + return NO_ERROR; + } break; + case START_PREVIEW: { + CHECK_INTERFACE(ICamera, data, reply); + reply->writeInt32(startPreview()); + return NO_ERROR; + } break; + case STOP_PREVIEW: { + CHECK_INTERFACE(ICamera, data, reply); + stopPreview(); + return NO_ERROR; + } break; + case AUTO_FOCUS: { + CHECK_INTERFACE(ICamera, data, reply); + reply->writeInt32(autoFocus()); + return NO_ERROR; + } break; + case TAKE_PICTURE: { + CHECK_INTERFACE(ICamera, data, reply); + reply->writeInt32(takePicture()); + return NO_ERROR; + } break; + case SET_PARAMETERS: { + CHECK_INTERFACE(ICamera, data, reply); + String8 params(data.readString8()); + reply->writeInt32(setParameters(params)); + return NO_ERROR; + } break; + case GET_PARAMETERS: { + CHECK_INTERFACE(ICamera, data, reply); + reply->writeString8(getParameters()); + return NO_ERROR; + } break; + default: + return BBinder::onTransact(code, data, reply, flags); + } +} + +// ---------------------------------------------------------------------------- + +}; // namespace android + diff --git a/libs/ui/ICameraClient.cpp b/libs/ui/ICameraClient.cpp new file mode 100644 index 0000000..3737034 --- /dev/null +++ b/libs/ui/ICameraClient.cpp @@ -0,0 +1,153 @@ +/* +** +** Copyright 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. +*/ + +#include <stdint.h> +#include <sys/types.h> + +#include <ui/ICameraClient.h> + +namespace android { + +enum { + SHUTTER_CALLBACK = IBinder::FIRST_CALL_TRANSACTION, + RAW_CALLBACK, + JPEG_CALLBACK, + FRAME_CALLBACK, + ERROR_CALLBACK, + AUTOFOCUS_CALLBACK +}; + +class BpCameraClient: public BpInterface<ICameraClient> +{ +public: + BpCameraClient(const sp<IBinder>& impl) + : BpInterface<ICameraClient>(impl) + { + } + + // callback to let the app know the shutter has closed, ideal for playing the shutter sound + void shutterCallback() + { + Parcel data, reply; + data.writeInterfaceToken(ICameraClient::getInterfaceDescriptor()); + remote()->transact(SHUTTER_CALLBACK, data, &reply, IBinder::FLAG_ONEWAY); + } + + // callback from camera service to app with picture data + void rawCallback(const sp<IMemory>& picture) + { + Parcel data, reply; + data.writeInterfaceToken(ICameraClient::getInterfaceDescriptor()); + data.writeStrongBinder(picture->asBinder()); + remote()->transact(RAW_CALLBACK, data, &reply, IBinder::FLAG_ONEWAY); + } + + // callback from camera service to app with picture data + void jpegCallback(const sp<IMemory>& picture) + { + Parcel data, reply; + data.writeInterfaceToken(ICameraClient::getInterfaceDescriptor()); + data.writeStrongBinder(picture->asBinder()); + remote()->transact(JPEG_CALLBACK, data, &reply, IBinder::FLAG_ONEWAY); + } + + // callback from camera service to app with video frame data + void frameCallback(const sp<IMemory>& frame) + { + Parcel data, reply; + data.writeInterfaceToken(ICameraClient::getInterfaceDescriptor()); + data.writeStrongBinder(frame->asBinder()); + remote()->transact(FRAME_CALLBACK, data, &reply, IBinder::FLAG_ONEWAY); + } + + // callback from camera service to app to report error + void errorCallback(status_t error) + { + Parcel data, reply; + data.writeInterfaceToken(ICameraClient::getInterfaceDescriptor()); + data.writeInt32(error); + remote()->transact(ERROR_CALLBACK, data, &reply, IBinder::FLAG_ONEWAY); + } + + // callback from camera service to app to report autofocus completion + void autoFocusCallback(bool focused) + { + Parcel data, reply; + data.writeInterfaceToken(ICameraClient::getInterfaceDescriptor()); + data.writeInt32(focused); + remote()->transact(AUTOFOCUS_CALLBACK, data, &reply, IBinder::FLAG_ONEWAY); + } +}; + +IMPLEMENT_META_INTERFACE(CameraClient, "android.hardware.ICameraClient"); + +// ---------------------------------------------------------------------- + +#define CHECK_INTERFACE(interface, data, reply) \ + do { if (!data.enforceInterface(interface::getInterfaceDescriptor())) { \ + LOGW("Call incorrectly routed to " #interface); \ + return PERMISSION_DENIED; \ + } } while (0) + +status_t BnCameraClient::onTransact( + uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) +{ + switch(code) { + case SHUTTER_CALLBACK: { + CHECK_INTERFACE(ICameraClient, data, reply); + shutterCallback(); + return NO_ERROR; + } break; + case RAW_CALLBACK: { + CHECK_INTERFACE(ICameraClient, data, reply); + sp<IMemory> picture = interface_cast<IMemory>(data.readStrongBinder()); + rawCallback(picture); + return NO_ERROR; + } break; + case JPEG_CALLBACK: { + CHECK_INTERFACE(ICameraClient, data, reply); + sp<IMemory> picture = interface_cast<IMemory>(data.readStrongBinder()); + jpegCallback(picture); + return NO_ERROR; + } break; + case FRAME_CALLBACK: { + CHECK_INTERFACE(ICameraClient, data, reply); + sp<IMemory> frame = interface_cast<IMemory>(data.readStrongBinder()); + frameCallback(frame); + return NO_ERROR; + } break; + case ERROR_CALLBACK: { + CHECK_INTERFACE(ICameraClient, data, reply); + status_t error = data.readInt32(); + errorCallback(error); + return NO_ERROR; + } break; + case AUTOFOCUS_CALLBACK: { + CHECK_INTERFACE(ICameraClient, data, reply); + bool focused = (bool)data.readInt32(); + autoFocusCallback(focused); + return NO_ERROR; + } break; + default: + return BBinder::onTransact(code, data, reply, flags); + } +} + +// ---------------------------------------------------------------------------- + +}; // namespace android + diff --git a/libs/ui/ICameraService.cpp b/libs/ui/ICameraService.cpp new file mode 100644 index 0000000..e5687fe --- /dev/null +++ b/libs/ui/ICameraService.cpp @@ -0,0 +1,77 @@ +/* +** +** Copyright 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. +*/ + +#include <stdint.h> +#include <sys/types.h> + +#include <utils/Parcel.h> +#include <utils/IPCThreadState.h> +#include <utils/IServiceManager.h> + +#include <ui/ICameraService.h> + +namespace android { + +class BpCameraService: public BpInterface<ICameraService> +{ +public: + BpCameraService(const sp<IBinder>& impl) + : BpInterface<ICameraService>(impl) + { + } + + // connect to camera service + virtual sp<ICamera> connect(const sp<ICameraClient>& cameraClient) + { + Parcel data, reply; + data.writeInterfaceToken(ICameraService::getInterfaceDescriptor()); + data.writeStrongBinder(cameraClient->asBinder()); + remote()->transact(BnCameraService::CONNECT, data, &reply); + return interface_cast<ICamera>(reply.readStrongBinder()); + } +}; + +IMPLEMENT_META_INTERFACE(CameraService, "android.hardware.ICameraService"); + +// ---------------------------------------------------------------------- + +#define CHECK_INTERFACE(interface, data, reply) \ + do { if (!data.enforceInterface(interface::getInterfaceDescriptor())) { \ + LOGW("Call incorrectly routed to " #interface); \ + return PERMISSION_DENIED; \ + } } while (0) + +status_t BnCameraService::onTransact( + uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) +{ + switch(code) { + case CONNECT: { + CHECK_INTERFACE(ICameraService, data, reply); + sp<ICameraClient> cameraClient = interface_cast<ICameraClient>(data.readStrongBinder()); + sp<ICamera> camera = connect(cameraClient); + reply->writeStrongBinder(camera->asBinder()); + return NO_ERROR; + } break; + default: + return BBinder::onTransact(code, data, reply, flags); + } +} + +// ---------------------------------------------------------------------------- + +}; // namespace android + diff --git a/libs/ui/ISurface.cpp b/libs/ui/ISurface.cpp new file mode 100644 index 0000000..817f4d9 --- /dev/null +++ b/libs/ui/ISurface.cpp @@ -0,0 +1,117 @@ +/* + * 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 <stdio.h> +#include <stdint.h> +#include <sys/types.h> + +#include <utils/Parcel.h> +#include <utils/IMemory.h> + +#include <ui/ISurface.h> + + +namespace android { + +enum { + REGISTER_BUFFERS = IBinder::FIRST_CALL_TRANSACTION, + UNREGISTER_BUFFERS, + POST_BUFFER, // one-way transaction +}; + +class BpSurface : public BpInterface<ISurface> +{ +public: + BpSurface(const sp<IBinder>& impl) + : BpInterface<ISurface>(impl) + { + } + + virtual status_t registerBuffers(int w, int h, int hstride, int vstride, + PixelFormat format, const sp<IMemoryHeap>& heap) + { + Parcel data, reply; + data.writeInterfaceToken(ISurface::getInterfaceDescriptor()); + data.writeInt32(w); + data.writeInt32(h); + data.writeInt32(hstride); + data.writeInt32(vstride); + data.writeInt32(format); + data.writeStrongBinder(heap->asBinder()); + remote()->transact(REGISTER_BUFFERS, data, &reply); + status_t result = reply.readInt32(); + return result; + } + + virtual void postBuffer(ssize_t offset) + { + Parcel data, reply; + data.writeInterfaceToken(ISurface::getInterfaceDescriptor()); + data.writeInt32(offset); + remote()->transact(POST_BUFFER, data, &reply, IBinder::FLAG_ONEWAY); + } + + virtual void unregisterBuffers() + { + Parcel data, reply; + data.writeInterfaceToken(ISurface::getInterfaceDescriptor()); + remote()->transact(UNREGISTER_BUFFERS, data, &reply); + } +}; + +IMPLEMENT_META_INTERFACE(Surface, "android.ui.ISurface"); + +// ---------------------------------------------------------------------- + +#define CHECK_INTERFACE(interface, data, reply) \ + do { if (!data.enforceInterface(interface::getInterfaceDescriptor())) { \ + LOGW("Call incorrectly routed to " #interface); \ + return PERMISSION_DENIED; \ + } } while (0) + +status_t BnSurface::onTransact( + uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) +{ + switch(code) { + case REGISTER_BUFFERS: { + CHECK_INTERFACE(ISurface, data, reply); + int w = data.readInt32(); + int h = data.readInt32(); + int hs= data.readInt32(); + int vs= data.readInt32(); + PixelFormat f = data.readInt32(); + sp<IMemoryHeap> heap(interface_cast<IMemoryHeap>(data.readStrongBinder())); + status_t err = registerBuffers(w,h,hs,vs,f,heap); + reply->writeInt32(err); + return NO_ERROR; + } break; + case UNREGISTER_BUFFERS: { + CHECK_INTERFACE(ISurface, data, reply); + unregisterBuffers(); + return NO_ERROR; + } break; + case POST_BUFFER: { + CHECK_INTERFACE(ISurface, data, reply); + ssize_t offset = data.readInt32(); + postBuffer(offset); + return NO_ERROR; + } break; + default: + return BBinder::onTransact(code, data, reply, flags); + } +} + +}; // namespace android diff --git a/libs/ui/ISurfaceComposer.cpp b/libs/ui/ISurfaceComposer.cpp new file mode 100644 index 0000000..0fea6f9 --- /dev/null +++ b/libs/ui/ISurfaceComposer.cpp @@ -0,0 +1,277 @@ +/* + * 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. + */ + +// tag as surfaceflinger +#define LOG_TAG "SurfaceFlinger" + +#include <stdint.h> +#include <sys/types.h> + +#include <utils/Parcel.h> +#include <utils/IMemory.h> +#include <utils/IPCThreadState.h> +#include <utils/IServiceManager.h> + +#include <ui/ISurfaceComposer.h> +#include <ui/DisplayInfo.h> + +// --------------------------------------------------------------------------- + +#define LIKELY( exp ) (__builtin_expect( (exp) != 0, true )) +#define UNLIKELY( exp ) (__builtin_expect( (exp) != 0, false )) + +// --------------------------------------------------------------------------- + +namespace android { + +class BpSurfaceComposer : public BpInterface<ISurfaceComposer> +{ +public: + BpSurfaceComposer(const sp<IBinder>& impl) + : BpInterface<ISurfaceComposer>(impl) + { + } + + virtual sp<ISurfaceFlingerClient> createConnection() + { + uint32_t n; + Parcel data, reply; + data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); + remote()->transact(BnSurfaceComposer::CREATE_CONNECTION, data, &reply); + return interface_cast<ISurfaceFlingerClient>(reply.readStrongBinder()); + } + + virtual sp<IMemory> getCblk() const + { + Parcel data, reply; + data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); + remote()->transact(BnSurfaceComposer::GET_CBLK, data, &reply); + return interface_cast<IMemory>(reply.readStrongBinder()); + } + + virtual void openGlobalTransaction() + { + Parcel data, reply; + data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); + remote()->transact(BnSurfaceComposer::OPEN_GLOBAL_TRANSACTION, data, &reply); + } + + virtual void closeGlobalTransaction() + { + Parcel data, reply; + data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); + remote()->transact(BnSurfaceComposer::CLOSE_GLOBAL_TRANSACTION, data, &reply); + } + + virtual status_t freezeDisplay(DisplayID dpy, uint32_t flags) + { + Parcel data, reply; + data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); + data.writeInt32(dpy); + data.writeInt32(flags); + remote()->transact(BnSurfaceComposer::FREEZE_DISPLAY, data, &reply); + return reply.readInt32(); + } + + virtual status_t unfreezeDisplay(DisplayID dpy, uint32_t flags) + { + Parcel data, reply; + data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); + data.writeInt32(dpy); + data.writeInt32(flags); + remote()->transact(BnSurfaceComposer::UNFREEZE_DISPLAY, data, &reply); + return reply.readInt32(); + } + + virtual int setOrientation(DisplayID dpy, int orientation) + { + Parcel data, reply; + data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); + data.writeInt32(dpy); + data.writeInt32(orientation); + remote()->transact(BnSurfaceComposer::SET_ORIENTATION, data, &reply); + return reply.readInt32(); + } + + virtual void bootFinished() + { + Parcel data, reply; + data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); + remote()->transact(BnSurfaceComposer::BOOT_FINISHED, data, &reply); + } + + virtual status_t requestGPU( + const sp<IGPUCallback>& callback, gpu_info_t* gpu) + { + Parcel data, reply; + data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); + data.writeStrongBinder(callback->asBinder()); + remote()->transact(BnSurfaceComposer::REQUEST_GPU, data, &reply); + gpu->regs = interface_cast<IMemory>(reply.readStrongBinder()); + gpu->count = reply.readInt32(); + + // FIXME: for now, we don't dynamically allocate the regions array + size_t maxCount = sizeof(gpu->regions)/sizeof(*gpu->regions); + if (gpu->count > maxCount) + return BAD_VALUE; + + for (size_t i=0 ; i<gpu->count ; i++) { + gpu->regions[i].region = interface_cast<IMemory>(reply.readStrongBinder()); + gpu->regions[i].reserved = reply.readInt32(); + } + return reply.readInt32(); + } + + virtual status_t revokeGPU() + { + Parcel data, reply; + data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); + remote()->transact(BnSurfaceComposer::REVOKE_GPU, data, &reply); + return reply.readInt32(); + } + + virtual void signal() const + { + Parcel data, reply; + data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); + remote()->transact(BnSurfaceComposer::SIGNAL, data, &reply, IBinder::FLAG_ONEWAY); + } +}; + +IMPLEMENT_META_INTERFACE(SurfaceComposer, "android.ui.ISurfaceComposer"); + +// ---------------------------------------------------------------------- + +#define CHECK_INTERFACE(interface, data, reply) \ + do { if (!data.enforceInterface(interface::getInterfaceDescriptor())) { \ + LOGW("Call incorrectly routed to " #interface); \ + return PERMISSION_DENIED; \ + } } while (0) + +status_t BnSurfaceComposer::onTransact( + uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) +{ + status_t err = BnInterface<ISurfaceComposer>::onTransact(code, data, reply, flags); + if (err == NO_ERROR) + return err; + + CHECK_INTERFACE(ISurfaceComposer, data, reply); + + switch(code) { + case CREATE_CONNECTION: { + sp<IBinder> b = createConnection()->asBinder(); + reply->writeStrongBinder(b); + } break; + case OPEN_GLOBAL_TRANSACTION: { + openGlobalTransaction(); + } break; + case CLOSE_GLOBAL_TRANSACTION: { + closeGlobalTransaction(); + } break; + case SET_ORIENTATION: { + DisplayID dpy = data.readInt32(); + int orientation = data.readInt32(); + reply->writeInt32( setOrientation(dpy, orientation) ); + } break; + case FREEZE_DISPLAY: { + DisplayID dpy = data.readInt32(); + uint32_t flags = data.readInt32(); + reply->writeInt32( freezeDisplay(dpy, flags) ); + } break; + case UNFREEZE_DISPLAY: { + DisplayID dpy = data.readInt32(); + uint32_t flags = data.readInt32(); + reply->writeInt32( unfreezeDisplay(dpy, flags) ); + } break; + case BOOT_FINISHED: { + bootFinished(); + } break; + case REVOKE_GPU: { + reply->writeInt32( revokeGPU() ); + } break; + case SIGNAL: { + signal(); + } break; + case GET_CBLK: { + sp<IBinder> b = getCblk()->asBinder(); + reply->writeStrongBinder(b); + } break; + case REQUEST_GPU: { + // TODO: this should be protected by a permission + gpu_info_t info; + sp<IGPUCallback> callback + = interface_cast<IGPUCallback>(data.readStrongBinder()); + status_t res = requestGPU(callback, &info); + + // FIXME: for now, we don't dynamically allocate the regions array + size_t maxCount = sizeof(info.regions)/sizeof(*info.regions); + if (info.count > maxCount) + return BAD_VALUE; + + reply->writeStrongBinder(info.regs->asBinder()); + reply->writeInt32(info.count); + for (size_t i=0 ; i<info.count ; i++) { + reply->writeStrongBinder(info.regions[i].region->asBinder()); + reply->writeInt32(info.regions[i].reserved); + } + reply->writeInt32(res); + } break; + default: + return UNKNOWN_TRANSACTION; + } + return NO_ERROR; +} + +// ---------------------------------------------------------------------------- + +enum { + // Note: BOOT_FINISHED must remain this value, it is called by ActivityManagerService. + GPU_LOST = IBinder::FIRST_CALL_TRANSACTION +}; + +class BpGPUCallback : public BpInterface<IGPUCallback> +{ +public: + BpGPUCallback(const sp<IBinder>& impl) + : BpInterface<IGPUCallback>(impl) + { + } + + virtual void gpuLost() + { + Parcel data, reply; + data.writeInterfaceToken(IGPUCallback::getInterfaceDescriptor()); + remote()->transact(GPU_LOST, data, &reply, IBinder::FLAG_ONEWAY); + } +}; + +IMPLEMENT_META_INTERFACE(GPUCallback, "android.ui.IGPUCallback"); + +status_t BnGPUCallback::onTransact( + uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) +{ + switch(code) { + case GPU_LOST: { + CHECK_INTERFACE(IGPUCallback, data, reply); + gpuLost(); + return NO_ERROR; + } break; + default: + return BBinder::onTransact(code, data, reply, flags); + } +} + +}; diff --git a/libs/ui/ISurfaceFlingerClient.cpp b/libs/ui/ISurfaceFlingerClient.cpp new file mode 100644 index 0000000..9444af7 --- /dev/null +++ b/libs/ui/ISurfaceFlingerClient.cpp @@ -0,0 +1,210 @@ +/* + * 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. + */ + +// tag as surfaceflinger +#define LOG_TAG "SurfaceFlinger" + +#include <stdio.h> +#include <stdint.h> +#include <sys/types.h> + +#include <utils/Parcel.h> +#include <utils/IMemory.h> +#include <utils/IPCThreadState.h> +#include <utils/IServiceManager.h> + +#include <ui/ISurface.h> +#include <ui/ISurfaceFlingerClient.h> +#include <ui/Point.h> +#include <ui/Rect.h> + +#include <private/ui/LayerState.h> + +// --------------------------------------------------------------------------- + +#define LIKELY( exp ) (__builtin_expect( (exp) != 0, true )) +#define UNLIKELY( exp ) (__builtin_expect( (exp) != 0, false )) + +// --------------------------------------------------------------------------- + +namespace android { + +enum { + GET_CBLK = IBinder::FIRST_CALL_TRANSACTION, + CREATE_SURFACE, + DESTROY_SURFACE, + SET_STATE +}; + +class BpSurfaceFlingerClient : public BpInterface<ISurfaceFlingerClient> +{ +public: + BpSurfaceFlingerClient(const sp<IBinder>& impl) + : BpInterface<ISurfaceFlingerClient>(impl) + { + } + + virtual void getControlBlocks(sp<IMemory>* ctl) const + { + Parcel data, reply; + data.writeInterfaceToken(ISurfaceFlingerClient::getInterfaceDescriptor()); + remote()->transact(GET_CBLK, data, &reply); + *ctl = interface_cast<IMemory>(reply.readStrongBinder()); + } + + virtual sp<ISurface> createSurface( surface_data_t* params, + int pid, + DisplayID display, + uint32_t w, + uint32_t h, + PixelFormat format, + uint32_t flags) + { + Parcel data, reply; + data.writeInterfaceToken(ISurfaceFlingerClient::getInterfaceDescriptor()); + data.writeInt32(pid); + data.writeInt32(display); + data.writeInt32(w); + data.writeInt32(h); + data.writeInt32(format); + data.writeInt32(flags); + remote()->transact(CREATE_SURFACE, data, &reply); + params->readFromParcel(data); + return interface_cast<ISurface>(reply.readStrongBinder()); + } + + virtual status_t destroySurface(SurfaceID sid) + { + Parcel data, reply; + data.writeInterfaceToken(ISurfaceFlingerClient::getInterfaceDescriptor()); + data.writeInt32(sid); + remote()->transact(DESTROY_SURFACE, data, &reply); + return reply.readInt32(); + } + + virtual status_t setState(int32_t count, const layer_state_t* states) + { + Parcel data, reply; + data.writeInterfaceToken(ISurfaceFlingerClient::getInterfaceDescriptor()); + data.writeInt32(count); + for (int i=0 ; i<count ; i++) + states[i].write(data); + remote()->transact(SET_STATE, data, &reply); + return reply.readInt32(); + } +}; + +IMPLEMENT_META_INTERFACE(SurfaceFlingerClient, "android.ui.ISurfaceFlingerClient"); + +// ---------------------------------------------------------------------- + +#define CHECK_INTERFACE(interface, data, reply) \ + do { if (!data.enforceInterface(interface::getInterfaceDescriptor())) { \ + LOGW("Call incorrectly routed to " #interface); \ + return PERMISSION_DENIED; \ + } } while (0) + +status_t BnSurfaceFlingerClient::onTransact( + uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) +{ + // codes that don't require permission check + + switch(code) { + case GET_CBLK: { + CHECK_INTERFACE(ISurfaceFlingerClient, data, reply); + sp<IMemory> ctl; + getControlBlocks(&ctl); + reply->writeStrongBinder(ctl->asBinder()); + return NO_ERROR; + } break; + } + + // these must be checked + + IPCThreadState* ipc = IPCThreadState::self(); + const int pid = ipc->getCallingPid(); + const int self_pid = getpid(); + if (UNLIKELY(pid != self_pid)) { + // we're called from a different process, do the real check + if (!checkCallingPermission( + String16("android.permission.ACCESS_SURFACE_FLINGER"))) + { + const int uid = ipc->getCallingUid(); + LOGE("Permission Denial: " + "can't openGlobalTransaction pid=%d, uid=%d", pid, uid); + return PERMISSION_DENIED; + } + } + + switch(code) { + case CREATE_SURFACE: { + CHECK_INTERFACE(ISurfaceFlingerClient, data, reply); + surface_data_t params; + int32_t pid = data.readInt32(); + DisplayID display = data.readInt32(); + uint32_t w = data.readInt32(); + uint32_t h = data.readInt32(); + PixelFormat format = data.readInt32(); + uint32_t flags = data.readInt32(); + sp<ISurface> s = createSurface(¶ms, pid, display, w, h, format, flags); + params.writeToParcel(reply); + reply->writeStrongBinder(s->asBinder()); + return NO_ERROR; + } break; + case DESTROY_SURFACE: { + CHECK_INTERFACE(ISurfaceFlingerClient, data, reply); + reply->writeInt32( destroySurface( data.readInt32() ) ); + return NO_ERROR; + } break; + case SET_STATE: { + CHECK_INTERFACE(ISurfaceFlingerClient, data, reply); + int32_t count = data.readInt32(); + layer_state_t* states = new layer_state_t[count]; + for (int i=0 ; i<count ; i++) + states[i].read(data); + status_t err = setState(count, states); + delete [] states; + reply->writeInt32(err); + return NO_ERROR; + } break; + default: + return BBinder::onTransact(code, data, reply, flags); + } +} + +// ---------------------------------------------------------------------- + +status_t ISurfaceFlingerClient::surface_data_t::readFromParcel(const Parcel& parcel) +{ + token = parcel.readInt32(); + identity = parcel.readInt32(); + type = parcel.readInt32(); + heap[0] = interface_cast<IMemoryHeap>(parcel.readStrongBinder()); + heap[1] = interface_cast<IMemoryHeap>(parcel.readStrongBinder()); + return NO_ERROR; +} + +status_t ISurfaceFlingerClient::surface_data_t::writeToParcel(Parcel* parcel) const +{ + parcel->writeInt32(token); + parcel->writeInt32(identity); + parcel->writeInt32(type); + parcel->writeStrongBinder(heap[0]!=0 ? heap[0]->asBinder() : NULL); + parcel->writeStrongBinder(heap[1]!=0 ? heap[1]->asBinder() : NULL); + return NO_ERROR; +} + +}; // namespace android diff --git a/libs/ui/KeyCharacterMap.cpp b/libs/ui/KeyCharacterMap.cpp new file mode 100644 index 0000000..e891181 --- /dev/null +++ b/libs/ui/KeyCharacterMap.cpp @@ -0,0 +1,263 @@ +#define LOG_TAG "KeyCharacterMap" + +#include <ui/KeyCharacterMap.h> +#include <cutils/properties.h> + +#include <utils/Log.h> +#include <sys/types.h> +#include <unistd.h> +#include <stdlib.h> +#include <fcntl.h> +#include <limits.h> +#include <string.h> + +struct Header +{ + char magic[8]; + unsigned int endian; + unsigned int version; + unsigned int keycount; + unsigned char kbdtype; + char padding[11]; +}; + +KeyCharacterMap::KeyCharacterMap() +{ +} + +KeyCharacterMap::~KeyCharacterMap() +{ + free(m_keys); +} + +unsigned short +KeyCharacterMap::get(int keycode, int meta) +{ + Key* k = find_key(keycode); + if (k != NULL) { + return k->data[meta & META_MASK]; + } + return 0; +} + +unsigned short +KeyCharacterMap::getNumber(int keycode) +{ + Key* k = find_key(keycode); + if (k != NULL) { + return k->number; + } + return 0; +} + +unsigned short +KeyCharacterMap::getMatch(int keycode, const unsigned short* chars, + int charsize, uint32_t modifiers) +{ + Key* k = find_key(keycode); + modifiers &= 3; // ignore the SYM key because we don't have keymap entries for it + if (k != NULL) { + const uint16_t* data = k->data; + for (int j=0; j<charsize; j++) { + uint16_t c = chars[j]; + for (int i=0; i<(META_MASK + 1); i++) { + if ((modifiers == 0) || ((modifiers & i) != 0)) { + if (c == data[i]) { + return c; + } + } + } + } + } + return 0; +} + +unsigned short +KeyCharacterMap::getDisplayLabel(int keycode) +{ + Key* k = find_key(keycode); + if (k != NULL) { + return k->display_label; + } + return 0; +} + +bool +KeyCharacterMap::getKeyData(int keycode, unsigned short *displayLabel, + unsigned short *number, unsigned short* results) +{ + Key* k = find_key(keycode); + if (k != NULL) { + memcpy(results, k->data, sizeof(short)*(META_MASK + 1)); + *number = k->number; + *displayLabel = k->display_label; + return true; + } else { + return false; + } +} + +bool +KeyCharacterMap::find_char(uint16_t c, uint32_t* key, uint32_t* mods) +{ + uint32_t N = m_keyCount; + for (int j=0; j<(META_MASK + 1); j++) { + Key const* keys = m_keys; + for (uint32_t i=0; i<N; i++) { + if (keys->data[j] == c) { + *key = keys->keycode; + *mods = j; + return true; + } + keys++; + } + } + return false; +} + +bool +KeyCharacterMap::getEvents(uint16_t* chars, size_t len, + Vector<int32_t>* keys, Vector<uint32_t>* modifiers) +{ + for (size_t i=0; i<len; i++) { + uint32_t k, mods; + if (find_char(chars[i], &k, &mods)) { + keys->add(k); + modifiers->add(mods); + } else { + return false; + } + } + return true; +} + +KeyCharacterMap::Key* +KeyCharacterMap::find_key(int keycode) +{ + Key* keys = m_keys; + int low = 0; + int high = m_keyCount - 1; + int mid; + int n; + while (low <= high) { + mid = (low + high) / 2; + n = keys[mid].keycode; + if (keycode < n) { + high = mid - 1; + } else if (keycode > n) { + low = mid + 1; + } else { + return keys + mid; + } + } + return NULL; +} + +KeyCharacterMap* +KeyCharacterMap::load(int id) +{ + KeyCharacterMap* rv = NULL; + char path[PATH_MAX]; + char propName[100]; + char dev[PROPERTY_VALUE_MAX]; + char tmpfn[PROPERTY_VALUE_MAX]; + int err; + const char* root = getenv("ANDROID_ROOT"); + + sprintf(propName, "hw.keyboards.%u.devname", id); + err = property_get(propName, dev, ""); + if (err > 0) { + // replace all the spaces with underscores + strcpy(tmpfn, dev); + for (char *p = strchr(tmpfn, ' '); p && *p; p = strchr(tmpfn, ' ')) + *p = '_'; + snprintf(path, sizeof(path), "%s/usr/keychars/%s.kcm.bin", root, tmpfn); + //LOGD("load: dev='%s' path='%s'\n", dev, path); + rv = try_file(path); + if (rv != NULL) { + return rv; + } + LOGW("Error loading keycharmap file '%s'. %s='%s'", path, propName, dev); + } else { + LOGW("No keyboard for id %d", id); + } + + snprintf(path, sizeof(path), "%s/usr/keychars/qwerty.kcm.bin", root); + rv = try_file(path); + if (rv == NULL) { + LOGE("Can't find any keycharmaps (also tried %s)", path); + return NULL; + } + LOGW("Using default keymap: %s", path); + + return rv; +} + +KeyCharacterMap* +KeyCharacterMap::try_file(const char* filename) +{ + KeyCharacterMap* rv = NULL; + Key* keys; + int fd; + off_t filesize; + Header header; + int err; + + fd = open(filename, O_RDONLY); + if (fd == -1) { + LOGW("Can't open keycharmap file"); + return NULL; + } + + filesize = lseek(fd, 0, SEEK_END); + lseek(fd, 0, SEEK_SET); + + // validate the header + if (filesize <= (off_t)sizeof(header)) { + LOGW("Bad keycharmap - filesize=%d\n", (int)filesize); + goto cleanup1; + } + + err = read(fd, &header, sizeof(header)); + if (err == -1) { + LOGW("Error reading keycharmap file"); + goto cleanup1; + } + + if (0 != memcmp(header.magic, "keychar", 8)) { + LOGW("Bad keycharmap magic token"); + goto cleanup1; + } + if (header.endian != 0x12345678) { + LOGW("Bad keycharmap endians"); + goto cleanup1; + } + if ((header.version & 0xff) != 2) { + LOGW("Only support keycharmap version 2 (got 0x%08x)", header.version); + goto cleanup1; + } + if (filesize < (off_t)(sizeof(Header)+(sizeof(Key)*header.keycount))) { + LOGW("Bad keycharmap file size\n"); + goto cleanup1; + } + + // read the key data + keys = (Key*)malloc(sizeof(Key)*header.keycount); + err = read(fd, keys, sizeof(Key)*header.keycount); + if (err == -1) { + LOGW("Error reading keycharmap file"); + free(keys); + goto cleanup1; + } + + // return the object + rv = new KeyCharacterMap; + rv->m_keyCount = header.keycount; + rv->m_keys = keys; + rv->m_type = header.kbdtype; + +cleanup1: + close(fd); + + return rv; +} diff --git a/libs/ui/KeyLayoutMap.cpp b/libs/ui/KeyLayoutMap.cpp new file mode 100644 index 0000000..15ae54c --- /dev/null +++ b/libs/ui/KeyLayoutMap.cpp @@ -0,0 +1,235 @@ +#define LOG_TAG "KeyLayoutMap" + +#include "KeyLayoutMap.h" +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <unistd.h> +#include <errno.h> +#include <utils/String8.h> +#include <stdlib.h> +#include <ui/KeycodeLabels.h> +#include <utils/Log.h> + +namespace android { + +KeyLayoutMap::KeyLayoutMap() + :m_status(NO_INIT), + m_keys() +{ +} + +KeyLayoutMap::~KeyLayoutMap() +{ +} + +static String8 +next_token(char const** p, int *line) +{ + bool begun = false; + const char* begin = *p; + const char* end = *p; + while (true) { + if (*end == '\n') { + (*line)++; + } + switch (*end) + { + case '#': + if (begun) { + *p = end; + return String8(begin, end-begin); + } else { + do { + begin++; + end++; + } while (*begin != '\0' && *begin != '\n'); + } + case '\0': + case ' ': + case '\n': + case '\r': + case '\t': + if (begun || (*end == '\0')) { + *p = end; + return String8(begin, end-begin); + } else { + begin++; + end++; + break; + } + default: + end++; + begun = true; + } + } +} + +static int32_t +token_to_value(const char *literal, const KeycodeLabel *list) +{ + while (list->literal) { + if (0 == strcmp(literal, list->literal)) { + return list->value; + } + list++; + } + return list->value; +} + +status_t +KeyLayoutMap::load(const char* filename) +{ + int fd = open(filename, O_RDONLY); + if (fd < 0) { + LOGE("error opening file=%s err=%s\n", filename, strerror(errno)); + m_status = errno; + return errno; + } + + off_t len = lseek(fd, 0, SEEK_END); + off_t errlen = lseek(fd, 0, SEEK_SET); + if (len < 0 || errlen < 0) { + close(fd); + LOGE("error seeking file=%s err=%s\n", filename, strerror(errno)); + m_status = errno; + return errno; + } + + char* buf = (char*)malloc(len+1); + if (read(fd, buf, len) != len) { + LOGE("error reading file=%s err=%s\n", filename, strerror(errno)); + m_status = errno != 0 ? errno : ((int)NOT_ENOUGH_DATA); + return errno != 0 ? errno : ((int)NOT_ENOUGH_DATA); + } + errno = 0; + buf[len] = '\0'; + + int32_t scancode = -1; + int32_t keycode = -1; + uint32_t flags = 0; + uint32_t tmp; + char* end; + status_t err = NO_ERROR; + int line = 1; + char const* p = buf; + enum { BEGIN, SCANCODE, KEYCODE, FLAG } state = BEGIN; + while (true) { + String8 token = next_token(&p, &line); + if (*p == '\0') { + break; + } + switch (state) + { + case BEGIN: + if (token == "key") { + state = SCANCODE; + } else { + LOGE("%s:%d: expected key, got '%s'\n", filename, line, + token.string()); + err = BAD_VALUE; + goto done; + } + break; + case SCANCODE: + scancode = strtol(token.string(), &end, 0); + if (*end != '\0') { + LOGE("%s:%d: expected scancode (a number), got '%s'\n", + filename, line, token.string()); + goto done; + } + //LOGI("%s:%d: got scancode %d\n", filename, line, scancode ); + state = KEYCODE; + break; + case KEYCODE: + keycode = token_to_value(token.string(), KEYCODES); + //LOGI("%s:%d: got keycode %d for %s\n", filename, line, keycode, token.string() ); + if (keycode == 0) { + LOGE("%s:%d: expected keycode, got '%s'\n", + filename, line, token.string()); + goto done; + } + state = FLAG; + break; + case FLAG: + if (token == "key") { + if (scancode != -1) { + //LOGI("got key decl scancode=%d keycode=%d" + // " flags=0x%08x\n", scancode, keycode, flags); + Key k = { keycode, flags }; + m_keys.add(scancode, k); + state = SCANCODE; + scancode = -1; + keycode = -1; + flags = 0; + break; + } + } + tmp = token_to_value(token.string(), FLAGS); + //LOGI("%s:%d: got flags %x for %s\n", filename, line, tmp, token.string() ); + if (tmp == 0) { + LOGE("%s:%d: expected flag, got '%s'\n", + filename, line, token.string()); + goto done; + } + flags |= tmp; + break; + } + } + if (state == FLAG && scancode != -1 ) { + //LOGI("got key decl scancode=%d keycode=%d" + // " flags=0x%08x\n", scancode, keycode, flags); + Key k = { keycode, flags }; + m_keys.add(scancode, k); + } + +done: + free(buf); + close(fd); + + m_status = err; + return err; +} + +status_t +KeyLayoutMap::map(int32_t scancode, int32_t *keycode, uint32_t *flags) const +{ + if (m_status != NO_ERROR) { + return m_status; + } + + ssize_t index = m_keys.indexOfKey(scancode); + if (index < 0) { + //LOGW("couldn't map scancode=%d\n", scancode); + return NAME_NOT_FOUND; + } + + const Key& k = m_keys.valueAt(index); + + *keycode = k.keycode; + *flags = k.flags; + + //LOGD("mapped scancode=%d to keycode=%d flags=0x%08x\n", scancode, + // keycode, flags); + + return NO_ERROR; +} + +status_t +KeyLayoutMap::findScancodes(int32_t keycode, Vector<int32_t>* outScancodes) const +{ + if (m_status != NO_ERROR) { + return m_status; + } + + const size_t N = m_keys.size(); + for (size_t i=0; i<N; i++) { + if (m_keys.valueAt(i).keycode == keycode) { + outScancodes->add(m_keys.keyAt(i)); + } + } + + return NO_ERROR; +} + +}; diff --git a/libs/ui/KeyLayoutMap.h b/libs/ui/KeyLayoutMap.h new file mode 100644 index 0000000..43f84ce --- /dev/null +++ b/libs/ui/KeyLayoutMap.h @@ -0,0 +1,31 @@ +#ifndef KEYLAYOUTMAP_H +#define KEYLAYOUTMAP_H + +#include <utils/KeyedVector.h> + +namespace android { + +class KeyLayoutMap +{ +public: + KeyLayoutMap(); + ~KeyLayoutMap(); + + status_t load(const char* filename); + + status_t map(int32_t scancode, int32_t *keycode, uint32_t *flags) const; + status_t findScancodes(int32_t keycode, Vector<int32_t>* outScancodes) const; + +private: + struct Key { + int32_t keycode; + uint32_t flags; + }; + + status_t m_status; + KeyedVector<int32_t,Key> m_keys; +}; + +}; + +#endif // KEYLAYOUTMAP_H diff --git a/libs/ui/LayerState.cpp b/libs/ui/LayerState.cpp new file mode 100644 index 0000000..0b6374b --- /dev/null +++ b/libs/ui/LayerState.cpp @@ -0,0 +1,53 @@ +/* + * 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. + */ + +#include <utils/Errors.h> +#include <utils/Parcel.h> +#include <private/ui/LayerState.h> + +namespace android { + +status_t layer_state_t::write(Parcel& output) const +{ + size_t size = sizeof(layer_state_t); + + //output.writeStrongBinder(surface->asBinder()); + //size -= sizeof(surface); + + transparentRegion.write(output); + size -= sizeof(transparentRegion); + + output.write(this, size); + + return NO_ERROR; +} + +status_t layer_state_t::read(const Parcel& input) +{ + size_t size = sizeof(layer_state_t); + + //surface = interface_cast<ISurface>(input.readStrongBinder()); + //size -= sizeof(surface); + + transparentRegion.read(input); + size -= sizeof(transparentRegion); + + input.read(this, size); + + return NO_ERROR; +} + +}; // namespace android diff --git a/libs/ui/MODULE_LICENSE_APACHE2 b/libs/ui/MODULE_LICENSE_APACHE2 new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/libs/ui/MODULE_LICENSE_APACHE2 diff --git a/libs/ui/NOTICE b/libs/ui/NOTICE new file mode 100644 index 0000000..c5b1efa --- /dev/null +++ b/libs/ui/NOTICE @@ -0,0 +1,190 @@ + + Copyright (c) 2005-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. + + 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. + + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + diff --git a/libs/ui/PixelFormat.cpp b/libs/ui/PixelFormat.cpp new file mode 100644 index 0000000..605c8ae --- /dev/null +++ b/libs/ui/PixelFormat.cpp @@ -0,0 +1,66 @@ +/* + * 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 <ui/PixelFormat.h> +#include <pixelflinger/format.h> + +namespace android { + +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; + + size_t numEntries; + const GGLFormat *i = gglGetPixelFormatTable(&numEntries) + format; + bool valid = uint32_t(format) < numEntries; + if (!valid) { + return BAD_INDEX; + } + + 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; +} + +}; // namespace android + diff --git a/libs/ui/Point.cpp b/libs/ui/Point.cpp new file mode 100644 index 0000000..438d49f --- /dev/null +++ b/libs/ui/Point.cpp @@ -0,0 +1,11 @@ +/* + * Point.cpp + * Android + * + * Created on 11/16/2006. + * Copyright 2005 The Android Open Source Project + * + */ + +#include <ui/Point.h> + diff --git a/libs/ui/Rect.cpp b/libs/ui/Rect.cpp new file mode 100644 index 0000000..99e68bb --- /dev/null +++ b/libs/ui/Rect.cpp @@ -0,0 +1,86 @@ +/* + * Rect.cpp + * Android + * + * Created on 10/14/05. + * Copyright 2005 The Android Open Source Project + * + */ + +#include <ui/Rect.h> + +namespace android { + +inline int min(int a, int b) { + return (a<b) ? a : b; +} + +inline int max(int a, int b) { + return (a>b) ? a : b; +} + +void Rect::makeInvalid() { + left = 0; + top = 0; + right = -1; + bottom = -1; +} + +bool Rect::operator < (const Rect& rhs) const +{ + if (top<rhs.top) { + return true; + } else if (top == rhs.top) { + if (left < rhs.left) { + return true; + } else if (left == rhs.left) { + if (bottom<rhs.bottom) { + return true; + } else if (bottom == rhs.bottom) { + if (right<rhs.right) { + return true; + } + } + } + } + return false; +} + +Rect& Rect::offsetTo(int x, int y) +{ + right -= left - x; + bottom -= top - y; + left = x; + top = y; + return *this; +} + +Rect& Rect::offsetBy(int x, int y) +{ + left += x; + top += y; + right+= x; + bottom+=y; + return *this; +} + +Rect Rect::operator + (const Point& rhs) const +{ + return Rect(left+rhs.x, top+rhs.y, right+rhs.x, bottom+rhs.y); +} + +Rect Rect::operator - (const Point& rhs) const +{ + return Rect(left-rhs.x, top-rhs.y, right-rhs.x, bottom-rhs.y); +} + +bool Rect::intersect(const Rect& with, Rect* result) const +{ + result->left = max(left, with.left); + result->top = max(top, with.top); + result->right = min(right, with.right); + result->bottom = min(bottom, with.bottom); + return !(result->isEmpty()); +} + +}; // namespace android diff --git a/libs/ui/Region.cpp b/libs/ui/Region.cpp new file mode 100644 index 0000000..3e07f2b --- /dev/null +++ b/libs/ui/Region.cpp @@ -0,0 +1,315 @@ +/* + * 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. + */ + +#define LOG_TAG "Region" + +#include <stdio.h> +#include <utils/Atomic.h> +#include <utils/Debug.h> +#include <utils/String8.h> +#include <ui/Region.h> +#include <corecg/SkRegion.h> +#include <corecg/SkRect.h> + +namespace android { + +// ---------------------------------------------------------------------------- + +Region::Region() +{ +} + +Region::Region(const Region& rhs) + : mRegion(rhs.mRegion) +{ +} + +Region::Region(const SkRegion& rhs) + : mRegion(rhs) +{ +} + +Region::~Region() +{ +} + +Region::Region(const Rect& rhs) +{ + set(rhs); +} + +Region::Region(const Parcel& parcel) +{ + read(parcel); +} + +Region::Region(const void* buffer) +{ + read(buffer); +} + +Region& Region::operator = (const Region& rhs) +{ + mRegion = rhs.mRegion; + return *this; +} + +const SkRegion& Region::toSkRegion() const +{ + return mRegion; +} + +Rect Region::bounds() const +{ + const SkIRect& b(mRegion.getBounds()); + return Rect(b.fLeft, b.fTop, b.fRight, b.fBottom); +} + +void Region::clear() +{ + mRegion.setEmpty(); +} + +void Region::set(const Rect& r) +{ + SkIRect ir; + ir.set(r.left, r.top, r.right, r.bottom); + mRegion.setRect(ir); +} + +// ---------------------------------------------------------------------------- + +Region& Region::orSelf(const Rect& r) +{ + SkIRect ir; + ir.set(r.left, r.top, r.right, r.bottom); + mRegion.op(ir, SkRegion::kUnion_Op); + return *this; +} + +Region& Region::andSelf(const Rect& r) +{ + SkIRect ir; + ir.set(r.left, r.top, r.right, r.bottom); + mRegion.op(ir, SkRegion::kIntersect_Op); + return *this; +} + +// ---------------------------------------------------------------------------- + +Region& Region::orSelf(const Region& rhs) { + mRegion.op(rhs.mRegion, SkRegion::kUnion_Op); + return *this; +} + +Region& Region::andSelf(const Region& rhs) { + mRegion.op(rhs.mRegion, SkRegion::kIntersect_Op); + return *this; +} + +Region& Region::subtractSelf(const Region& rhs) { + mRegion.op(rhs.mRegion, SkRegion::kDifference_Op); + return *this; +} + +Region& Region::translateSelf(int x, int y) { + if (x|y) mRegion.translate(x, y); + return *this; +} + +Region Region::merge(const Region& rhs) const { + Region result; + result.mRegion.op(mRegion, rhs.mRegion, SkRegion::kUnion_Op); + return result; +} + +Region Region::intersect(const Region& rhs) const { + Region result; + result.mRegion.op(mRegion, rhs.mRegion, SkRegion::kIntersect_Op); + return result; +} + +Region Region::subtract(const Region& rhs) const { + Region result; + result.mRegion.op(mRegion, rhs.mRegion, SkRegion::kDifference_Op); + return result; +} + +Region Region::translate(int x, int y) const { + Region result; + mRegion.translate(x, y, &result.mRegion); + return result; +} + +// ---------------------------------------------------------------------------- + +Region& Region::orSelf(const Region& rhs, int dx, int dy) { + SkRegion r(rhs.mRegion); + r.translate(dx, dy); + mRegion.op(r, SkRegion::kUnion_Op); + return *this; +} + +Region& Region::andSelf(const Region& rhs, int dx, int dy) { + SkRegion r(rhs.mRegion); + r.translate(dx, dy); + mRegion.op(r, SkRegion::kIntersect_Op); + return *this; +} + +Region& Region::subtractSelf(const Region& rhs, int dx, int dy) { + SkRegion r(rhs.mRegion); + r.translate(dx, dy); + mRegion.op(r, SkRegion::kDifference_Op); + return *this; +} + +Region Region::merge(const Region& rhs, int dx, int dy) const { + Region result; + SkRegion r(rhs.mRegion); + r.translate(dx, dy); + result.mRegion.op(mRegion, r, SkRegion::kUnion_Op); + return result; +} + +Region Region::intersect(const Region& rhs, int dx, int dy) const { + Region result; + SkRegion r(rhs.mRegion); + r.translate(dx, dy); + result.mRegion.op(mRegion, r, SkRegion::kIntersect_Op); + return result; +} + +Region Region::subtract(const Region& rhs, int dx, int dy) const { + Region result; + SkRegion r(rhs.mRegion); + r.translate(dx, dy); + result.mRegion.op(mRegion, r, SkRegion::kDifference_Op); + return result; +} + +// ---------------------------------------------------------------------------- + +Region::iterator::iterator(const Region& r) + : mIt(r.mRegion) +{ +} + +int Region::iterator::iterate(Rect* rect) +{ + if (mIt.done()) + return 0; + const SkIRect& r(mIt.rect()); + rect->left = r.fLeft; + rect->top = r.fTop; + rect->right = r.fRight; + rect->bottom= r.fBottom; + mIt.next(); + return 1; +} + +// ---------------------------------------------------------------------------- + +// we write a 4byte size ahead of the actual region, so we know how much we'll need for reading + +status_t Region::write(Parcel& parcel) const +{ + int32_t size = mRegion.flatten(NULL); + parcel.writeInt32(size); + mRegion.flatten(parcel.writeInplace(size)); + return NO_ERROR; +} + +status_t Region::read(const Parcel& parcel) +{ + size_t size = parcel.readInt32(); + mRegion.unflatten(parcel.readInplace(size)); + return NO_ERROR; +} + +ssize_t Region::write(void* buffer, size_t size) const +{ + size_t sizeNeeded = mRegion.flatten(NULL); + if (sizeNeeded > size) return NO_MEMORY; + return mRegion.flatten(buffer); +} + +ssize_t Region::read(const void* buffer) +{ + return mRegion.unflatten(buffer); +} + +ssize_t Region::writeEmpty(void* buffer, size_t size) +{ + if (size < 4) return NO_MEMORY; + // this needs to stay in sync with SkRegion + *static_cast<int32_t*>(buffer) = -1; + return 4; +} + +bool Region::isEmpty(void* buffer) +{ + // this needs to stay in sync with SkRegion + return *static_cast<int32_t*>(buffer) == -1; +} + +size_t Region::rects(Vector<Rect>& rectList) const +{ + rectList.clear(); + if (!isEmpty()) { + SkRegion::Iterator iterator(mRegion); + while( !iterator.done() ) { + const SkIRect& ir(iterator.rect()); + rectList.push(Rect(ir.fLeft, ir.fTop, ir.fRight, ir.fBottom)); + iterator.next(); + } + } + return rectList.size(); +} + +void Region::dump(String8& out, const char* what, uint32_t flags) const +{ + (void)flags; + Vector<Rect> r; + rects(r); + + size_t SIZE = 256; + char buffer[SIZE]; + + snprintf(buffer, SIZE, " Region %s (this=%p, count=%d)\n", what, this, r.size()); + out.append(buffer); + for (size_t i=0 ; i<r.size() ; i++) { + snprintf(buffer, SIZE, " [%3d, %3d, %3d, %3d]\n", + r[i].left, r[i].top,r[i].right,r[i].bottom); + out.append(buffer); + } +} + +void Region::dump(const char* what, uint32_t flags) const +{ + (void)flags; + Vector<Rect> r; + rects(r); + LOGD(" Region %s (this=%p, count=%d)\n", what, this, r.size()); + for (size_t i=0 ; i<r.size() ; i++) { + LOGD(" [%3d, %3d, %3d, %3d]\n", + r[i].left, r[i].top,r[i].right,r[i].bottom); + } +} + +// ---------------------------------------------------------------------------- + +}; // namespace android diff --git a/libs/ui/Surface.cpp b/libs/ui/Surface.cpp new file mode 100644 index 0000000..0a9aaad --- /dev/null +++ b/libs/ui/Surface.cpp @@ -0,0 +1,261 @@ +/* + * 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. + */ + +#define LOG_TAG "Surface" + +#include <stdint.h> +#include <unistd.h> +#include <fcntl.h> +#include <errno.h> +#include <sys/types.h> +#include <sys/stat.h> + +#include <utils/Atomic.h> +#include <utils/Errors.h> +#include <utils/threads.h> +#include <utils/IPCThreadState.h> +#include <utils/IMemory.h> +#include <utils/Log.h> + +#include <ui/ISurface.h> +#include <ui/Surface.h> +#include <ui/SurfaceComposerClient.h> +#include <ui/Rect.h> + +#include <private/ui/SharedState.h> +#include <private/ui/LayerState.h> + +namespace android { + +// --------------------------------------------------------------------------- + +Surface::Surface(const sp<SurfaceComposerClient>& client, + const sp<ISurface>& surface, + const ISurfaceFlingerClient::surface_data_t& data, + uint32_t w, uint32_t h, PixelFormat format, uint32_t flags, + bool owner) + : mClient(client), mSurface(surface), mMemoryType(data.type), + mToken(data.token), mIdentity(data.identity), + mFormat(format), mFlags(flags), mOwner(owner) +{ + mSwapRectangle.makeInvalid(); + mSurfaceHeapBase[0] = 0; + mSurfaceHeapBase[1] = 0; + mHeap[0] = data.heap[0]; + mHeap[1] = data.heap[1]; +} + +Surface::Surface(Surface const* rhs) + : mOwner(false) +{ + mToken = rhs->mToken; + mIdentity= rhs->mIdentity; + mClient = rhs->mClient; + mSurface = rhs->mSurface; + mHeap[0] = rhs->mHeap[0]; + mHeap[1] = rhs->mHeap[1]; + mMemoryType = rhs->mMemoryType; + mFormat = rhs->mFormat; + mFlags = rhs->mFlags; + mSurfaceHeapBase[0] = rhs->mSurfaceHeapBase[0]; + mSurfaceHeapBase[1] = rhs->mSurfaceHeapBase[1]; + mSwapRectangle.makeInvalid(); +} + +Surface::~Surface() +{ + if (mOwner && mToken>=0 && mClient!=0) { + mClient->destroySurface(mToken); + } + mClient.clear(); + mSurface.clear(); + mHeap[0].clear(); + mHeap[1].clear(); + IPCThreadState::self()->flushCommands(); +} + +sp<Surface> Surface::dup() const +{ + Surface const * r = this; + if (this && mOwner) { + // the only reason we need to do this is because of Java's garbage + // collector: because we're creating a copy of the Surface + // instead of a reference, we can garantee that when our last + // reference goes away, the real surface will be deleted. + // Without this hack (the code is correct too), we'd have to + // wait for a GC for the surface to go away. + r = new Surface(this); + } + return const_cast<Surface*>(r); +} + +status_t Surface::nextBuffer(SurfaceInfo* info) { + return mClient->nextBuffer(this, info); +} + +status_t Surface::lock(SurfaceInfo* info, bool blocking) { + return Surface::lock(info, NULL, blocking); +} + +status_t Surface::lock(SurfaceInfo* info, Region* dirty, bool blocking) { + if (heapBase(0) == 0) return INVALID_OPERATION; + if (heapBase(1) == 0) return INVALID_OPERATION; + return mClient->lockSurface(this, info, dirty, blocking); +} + +status_t Surface::unlockAndPost() { + if (heapBase(0) == 0) return INVALID_OPERATION; + if (heapBase(1) == 0) return INVALID_OPERATION; + return mClient->unlockAndPostSurface(this); +} + +status_t Surface::unlock() { + if (heapBase(0) == 0) return INVALID_OPERATION; + if (heapBase(1) == 0) return INVALID_OPERATION; + return mClient->unlockSurface(this); +} + +status_t Surface::setLayer(int32_t layer) { + return mClient->setLayer(this, layer); +} +status_t Surface::setPosition(int32_t x, int32_t y) { + return mClient->setPosition(this, x, y); +} +status_t Surface::setSize(uint32_t w, uint32_t h) { + return mClient->setSize(this, w, h); +} +status_t Surface::hide() { + return mClient->hide(this); +} +status_t Surface::show(int32_t layer) { + return mClient->show(this, layer); +} +status_t Surface::freeze() { + return mClient->freeze(this); +} +status_t Surface::unfreeze() { + return mClient->unfreeze(this); +} +status_t Surface::setFlags(uint32_t flags, uint32_t mask) { + return mClient->setFlags(this, flags, mask); +} +status_t Surface::setTransparentRegionHint(const Region& transparent) { + return mClient->setTransparentRegionHint(this, transparent); +} +status_t Surface::setAlpha(float alpha) { + return mClient->setAlpha(this, alpha); +} +status_t Surface::setMatrix(float dsdx, float dtdx, float dsdy, float dtdy) { + return mClient->setMatrix(this, dsdx, dtdx, dsdy, dtdy); +} +status_t Surface::setFreezeTint(uint32_t tint) { + return mClient->setFreezeTint(this, tint); +} + +Region Surface::dirtyRegion() const { + return mDirtyRegion; +} +void Surface::setDirtyRegion(const Region& region) const { + mDirtyRegion = region; +} +const Rect& Surface::swapRectangle() const { + return mSwapRectangle; +} +void Surface::setSwapRectangle(const Rect& r) { + mSwapRectangle = r; +} + +sp<Surface> Surface::readFromParcel(Parcel* parcel) +{ + sp<SurfaceComposerClient> client; + ISurfaceFlingerClient::surface_data_t data; + sp<IBinder> clientBinder= parcel->readStrongBinder(); + sp<ISurface> surface = interface_cast<ISurface>(parcel->readStrongBinder()); + data.heap[0] = interface_cast<IMemoryHeap>(parcel->readStrongBinder()); + data.heap[1] = interface_cast<IMemoryHeap>(parcel->readStrongBinder()); + data.type = parcel->readInt32(); + data.token = parcel->readInt32(); + data.identity = parcel->readInt32(); + PixelFormat format = parcel->readInt32(); + uint32_t flags = parcel->readInt32(); + + if (clientBinder != NULL) + client = SurfaceComposerClient::clientForConnection(clientBinder); + + return new Surface(client, surface, data, 0, 0, format, flags, false); +} + +status_t Surface::writeToParcel(const sp<Surface>& surface, Parcel* parcel) +{ + uint32_t flags=0; + uint32_t format=0; + SurfaceID token = -1; + uint32_t identity = 0; + sp<SurfaceComposerClient> client; + sp<ISurface> sur; + sp<IMemoryHeap> heap[2]; + int type = 0; + if (surface->isValid()) { + token = surface->mToken; + identity = surface->mIdentity; + client = surface->mClient; + sur = surface->mSurface; + heap[0] = surface->mHeap[0]; + heap[1] = surface->mHeap[1]; + type = surface->mMemoryType; + format = surface->mFormat; + flags = surface->mFlags; + } + parcel->writeStrongBinder(client!=0 ? client->connection() : NULL); + parcel->writeStrongBinder(sur!=0 ? sur->asBinder() : NULL); + parcel->writeStrongBinder(heap[0]!=0 ? heap[0]->asBinder() : NULL); + parcel->writeStrongBinder(heap[1]!=0 ? heap[1]->asBinder() : NULL); + parcel->writeInt32(type); + parcel->writeInt32(token); + parcel->writeInt32(identity); + parcel->writeInt32(format); + parcel->writeInt32(flags); + return NO_ERROR; +} + +bool Surface::isSameSurface(const sp<Surface>& lhs, const sp<Surface>& rhs) +{ + if (lhs == 0 || rhs == 0) + return false; + return lhs->mSurface->asBinder() == rhs->mSurface->asBinder(); +} + +void* Surface::heapBase(int i) const +{ + void* heapBase = mSurfaceHeapBase[i]; + // map lazily so it doesn't get mapped in clients that don't need it + if (heapBase == 0) { + const sp<IMemoryHeap>& heap(mHeap[i]); + if (heap != 0) { + heapBase = static_cast<uint8_t*>(heap->base()); + if (heapBase == MAP_FAILED) { + heapBase = NULL; + LOGE("Couldn't map Surface's heap (binder=%p, heap=%p)", + heap->asBinder().get(), heap.get()); + } + mSurfaceHeapBase[i] = heapBase; + } + } + return heapBase; +} + +}; // namespace android + diff --git a/libs/ui/SurfaceComposerClient.cpp b/libs/ui/SurfaceComposerClient.cpp new file mode 100644 index 0000000..9354a7a --- /dev/null +++ b/libs/ui/SurfaceComposerClient.cpp @@ -0,0 +1,1026 @@ +/* + * 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. + */ + +#define LOG_TAG "SurfaceComposerClient" + +#include <stdint.h> +#include <unistd.h> +#include <fcntl.h> +#include <errno.h> +#include <sys/types.h> +#include <sys/stat.h> + +#include <cutils/memory.h> + +#include <utils/Atomic.h> +#include <utils/Errors.h> +#include <utils/threads.h> +#include <utils/KeyedVector.h> +#include <utils/IPCThreadState.h> +#include <utils/IServiceManager.h> +#include <utils/IMemory.h> +#include <utils/Log.h> + +#include <ui/ISurfaceComposer.h> +#include <ui/ISurfaceFlingerClient.h> +#include <ui/ISurface.h> +#include <ui/SurfaceComposerClient.h> +#include <ui/DisplayInfo.h> +#include <ui/Rect.h> +#include <ui/Point.h> + +#include <private/ui/SharedState.h> +#include <private/ui/LayerState.h> +#include <private/ui/SurfaceFlingerSynchro.h> + +#include <pixelflinger/pixelflinger.h> + +#include <utils/BpBinder.h> + +#define VERBOSE(...) ((void)0) +//#define VERBOSE LOGD + +#define LIKELY( exp ) (__builtin_expect( (exp) != 0, true )) +#define UNLIKELY( exp ) (__builtin_expect( (exp) != 0, false )) + +namespace android { + +// --------------------------------------------------------------------------- + +// Must not be holding SurfaceComposerClient::mLock when acquiring gLock here. +static Mutex gLock; +static sp<ISurfaceComposer> gSurfaceManager; +static DefaultKeyedVector< sp<IBinder>, sp<SurfaceComposerClient> > gActiveConnections; +static SortedVector<sp<SurfaceComposerClient> > gOpenTransactions; +static sp<IMemory> gServerCblkMemory; +static volatile surface_flinger_cblk_t* gServerCblk; + +const sp<ISurfaceComposer>& _get_surface_manager() +{ + if (gSurfaceManager != 0) { + return gSurfaceManager; + } + + sp<IBinder> binder; + sp<IServiceManager> sm = defaultServiceManager(); + do { + binder = sm->getService(String16("SurfaceFlinger")); + if (binder == 0) { + LOGW("SurfaceFlinger not published, waiting..."); + usleep(500000); // 0.5 s + } + } while(binder == 0); + sp<ISurfaceComposer> sc(interface_cast<ISurfaceComposer>(binder)); + + Mutex::Autolock _l(gLock); + if (gSurfaceManager == 0) { + gSurfaceManager = sc; + } + return gSurfaceManager; +} + +static volatile surface_flinger_cblk_t const * get_cblk() +{ + if (gServerCblk == 0) { + const sp<ISurfaceComposer>& sm(_get_surface_manager()); + Mutex::Autolock _l(gLock); + if (gServerCblk == 0) { + gServerCblkMemory = sm->getCblk(); + LOGE_IF(gServerCblkMemory==0, "Can't get server control block"); + gServerCblk = (surface_flinger_cblk_t *)gServerCblkMemory->pointer(); + LOGE_IF(gServerCblk==0, "Can't get server control block address"); + } + } + return gServerCblk; +} + +// --------------------------------------------------------------------------- + +static void copyBlt(const GGLSurface& dst, + const GGLSurface& src, const Region& reg) +{ + Region::iterator iterator(reg); + if (iterator) { + // NOTE: dst and src must be the same format + Rect r; + const size_t bpp = bytesPerPixel(src.format); + const size_t dbpr = dst.stride * bpp; + const size_t sbpr = src.stride * bpp; + while (iterator.iterate(&r)) { + ssize_t h = r.bottom - r.top; + if (h) { + size_t size = (r.right - r.left) * bpp; + uint8_t* s = src.data + (r.left + src.stride * r.top) * bpp; + uint8_t* d = dst.data + (r.left + dst.stride * r.top) * bpp; + if (dbpr==sbpr && size==sbpr) { + size *= h; + h = 1; + } + do { + memcpy(d, s, size); + d += dbpr; + s += sbpr; + } while (--h > 0); + } + } + } +} + +// --------------------------------------------------------------------------- + +surface_flinger_cblk_t::surface_flinger_cblk_t() +{ +} + +// --------------------------------------------------------------------------- + +per_client_cblk_t::per_client_cblk_t() +{ +} + +// these functions are used by the clients +inline status_t per_client_cblk_t::validate(size_t i) const { + if (uint32_t(i) >= NUM_LAYERS_MAX) + return BAD_INDEX; + if (layers[i].swapState & eInvalidSurface) + return NO_MEMORY; + return NO_ERROR; +} + +int32_t per_client_cblk_t::lock_layer(size_t i, uint32_t flags) +{ + int32_t index; + uint32_t state; + int timeout = 0; + status_t result; + layer_cblk_t * const layer = layers + i; + const bool blocking = flags & BLOCKING; + const bool inspect = flags & INSPECT; + + do { + state = layer->swapState; + + if (UNLIKELY((state&(eFlipRequested|eNextFlipPending)) == eNextFlipPending)) { + LOGE("eNextFlipPending set but eFlipRequested not set, " + "layer=%d (lcblk=%p), state=%08x", + int(i), layer, int(state)); + return INVALID_OPERATION; + } + + if (UNLIKELY(state&eLocked)) { + LOGE("eLocked set when entering lock_layer(), " + "layer=%d (lcblk=%p), state=%08x", + int(i), layer, int(state)); + return WOULD_BLOCK; + } + + + if (state & (eFlipRequested | eNextFlipPending | eResizeRequested + | eInvalidSurface)) + { + int32_t resizeIndex; + Mutex::Autolock _l(lock); + // might block for a very short amount of time + // will never cause the server to block (trylock()) + + goto start_loop_here; + + // We block the client if: + // eNextFlipPending: we've used both buffers already, so we need to + // wait for one to become availlable. + // eResizeRequested: the buffer we're going to acquire is being + // resized. Block until it is done. + // eFlipRequested && eBusy: the buffer we're going to acquire is + // currently in use by the server. + // eInvalidSurface: this is a special case, we don't block in this + // case, we just return an error. + + while((state & (eNextFlipPending|eInvalidSurface)) || + (state & ((resizeIndex) ? eResizeBuffer1 : eResizeBuffer0)) || + ((state & (eFlipRequested|eBusy)) == (eFlipRequested|eBusy)) ) + { + if (state & eInvalidSurface) + return NO_MEMORY; + + if (!blocking) + return WOULD_BLOCK; + + timeout = 0; + result = cv.waitRelative(lock, seconds(1)); + if (__builtin_expect(result!=NO_ERROR, false)) { + const int newState = layer->swapState; + LOGW( "lock_layer timed out (is the CPU pegged?) " + "layer=%d, lcblk=%p, state=%08x (was %08x)", + int(i), layer, newState, int(state)); + timeout = newState != int(state); + } + + start_loop_here: + state = layer->swapState; + resizeIndex = (state&eIndex) ^ ((state&eFlipRequested)>>1); + } + + LOGW_IF(timeout, + "lock_layer() timed out but didn't appear to need " + "to be locked and we recovered " + "(layer=%d, lcblk=%p, state=%08x)", + int(i), layer, int(state)); + } + + // eFlipRequested is not set and cannot be set by another thread: it's + // safe to use the first buffer without synchronization. + + // Choose the index depending on eFlipRequested. + // When it's set, choose the 'other' buffer. + index = (state&eIndex) ^ ((state&eFlipRequested)>>1); + + // make sure this buffer is valid + if (layer->surface[index].bits_offset < 0) { + return status_t(layer->surface[index].bits_offset); + } + + if (inspect) { + // we just want to inspect this layer. don't lock it. + goto done; + } + + // last thing before we're done, we need to atomically lock the state + } while (android_atomic_cmpxchg(state, state|eLocked, &(layer->swapState))); + + VERBOSE("locked layer=%d (lcblk=%p), buffer=%d, state=0x%08x", + int(i), layer, int(index), int(state)); + + // store the index of the locked buffer (for client use only) + layer->flags &= ~eBufferIndex; + layer->flags |= ((index << eBufferIndexShift) & eBufferIndex); + +done: + return index; +} + +uint32_t per_client_cblk_t::unlock_layer_and_post(size_t i) +{ + // atomically set eFlipRequested and clear eLocked and optionnaly + // set eNextFlipPending if eFlipRequested was already set + + layer_cblk_t * const layer = layers + i; + int32_t oldvalue, newvalue; + do { + oldvalue = layer->swapState; + // get current value + + newvalue = oldvalue & ~eLocked; + // clear eLocked + + newvalue |= eFlipRequested; + // set eFlipRequested + + if (oldvalue & eFlipRequested) + newvalue |= eNextFlipPending; + // if eFlipRequested was alread set, set eNextFlipPending + + } while (android_atomic_cmpxchg(oldvalue, newvalue, &(layer->swapState))); + + VERBOSE("request pageflip for layer=%d, buffer=%d, state=0x%08x", + int(i), int((layer->flags & eBufferIndex) >> eBufferIndexShift), + int(newvalue)); + + // from this point, the server can kick in at anytime and use the first + // buffer, so we cannot use it anymore, and we must use the 'other' + // buffer instead (or wait if it is not availlable yet, see lock_layer). + + return newvalue; +} + +void per_client_cblk_t::unlock_layer(size_t i) +{ + layer_cblk_t * const layer = layers + i; + android_atomic_and(~eLocked, &layer->swapState); +} + +// --------------------------------------------------------------------------- + +static inline int compare_type( const layer_state_t& lhs, + const layer_state_t& rhs) { + if (lhs.surface < rhs.surface) return -1; + if (lhs.surface > rhs.surface) return 1; + return 0; +} + +SurfaceComposerClient::SurfaceComposerClient() +{ + const sp<ISurfaceComposer>& sm(_get_surface_manager()); + if (sm == 0) { + _init(0, 0); + return; + } + + _init(sm, sm->createConnection()); + + if (mClient != 0) { + Mutex::Autolock _l(gLock); + VERBOSE("Adding client %p to map", this); + gActiveConnections.add(mClient->asBinder(), this); + } +} + +SurfaceComposerClient::SurfaceComposerClient( + const sp<ISurfaceComposer>& sm, const sp<IBinder>& conn) +{ + _init(sm, interface_cast<ISurfaceFlingerClient>(conn)); +} + +void SurfaceComposerClient::_init( + const sp<ISurfaceComposer>& sm, const sp<ISurfaceFlingerClient>& conn) +{ + VERBOSE("Creating client %p, conn %p", this, conn.get()); + + mSignalServer = 0; + mPrebuiltLayerState = 0; + mTransactionOpen = 0; + mStatus = NO_ERROR; + mControl = 0; + + mClient = conn; + if (mClient == 0) { + mStatus = NO_INIT; + return; + } + + mClient->getControlBlocks(&mControlMemory); + mSignalServer = new SurfaceFlingerSynchro(sm); + mControl = static_cast<per_client_cblk_t *>(mControlMemory->pointer()); +} + +SurfaceComposerClient::~SurfaceComposerClient() +{ + VERBOSE("Destroying client %p, conn %p", this, mClient.get()); + dispose(); +} + +status_t SurfaceComposerClient::initCheck() const +{ + return mStatus; +} + +status_t SurfaceComposerClient::validateSurface( + per_client_cblk_t const* cblk, Surface const * surface) +{ + SurfaceID index = surface->ID(); + if (cblk == 0) { + LOGE("cblk is null (surface id=%d, identity=%u)", + index, surface->getIdentity()); + return NO_INIT; + } + + status_t err = cblk->validate(index); + if (err != NO_ERROR) { + LOGE("surface (id=%d, identity=%u) is invalid, err=%d (%s)", + index, surface->getIdentity(), err, strerror(-err)); + return err; + } + + if (surface->getIdentity() != uint32_t(cblk->layers[index].identity)) { + LOGE("using an invalid surface id=%d, identity=%u should be %d", + index, surface->getIdentity(), cblk->layers[index].identity); + return NO_INIT; + } + + return NO_ERROR; +} + +sp<IBinder> SurfaceComposerClient::connection() const +{ + return (mClient != 0) ? mClient->asBinder() : 0; +} + +sp<SurfaceComposerClient> +SurfaceComposerClient::clientForConnection(const sp<IBinder>& conn) +{ + sp<SurfaceComposerClient> client; + + { // scope for lock + Mutex::Autolock _l(gLock); + client = gActiveConnections.valueFor(conn); + } + + if (client == 0) { + // Need to make a new client. + const sp<ISurfaceComposer>& sm(_get_surface_manager()); + client = new SurfaceComposerClient(sm, conn); + if (client != 0 && client->initCheck() == NO_ERROR) { + Mutex::Autolock _l(gLock); + gActiveConnections.add(conn, client); + //LOGD("we have %d connections", gActiveConnections.size()); + } else { + client.clear(); + } + } + + return client; +} + +void SurfaceComposerClient::dispose() +{ + // this can be called more than once. + + sp<IMemory> controlMemory; + sp<ISurfaceFlingerClient> client; + sp<IMemoryHeap> surfaceHeap; + + { + Mutex::Autolock _lg(gLock); + Mutex::Autolock _lm(mLock); + + delete mSignalServer; + mSignalServer = 0; + + if (mClient != 0) { + client = mClient; + mClient.clear(); + + ssize_t i = gActiveConnections.indexOfKey(client->asBinder()); + if (i >= 0 && gActiveConnections.valueAt(i) == this) { + VERBOSE("Removing client %p from map at %d", this, int(i)); + gActiveConnections.removeItemsAt(i); + } + } + + delete mPrebuiltLayerState; + mPrebuiltLayerState = 0; + controlMemory = mControlMemory; + surfaceHeap = mSurfaceHeap; + mControlMemory.clear(); + mSurfaceHeap.clear(); + mControl = 0; + mStatus = NO_INIT; + } +} + +status_t SurfaceComposerClient::getDisplayInfo( + DisplayID dpy, DisplayInfo* info) +{ + if (uint32_t(dpy)>=NUM_DISPLAY_MAX) + return BAD_VALUE; + + volatile surface_flinger_cblk_t const * cblk = get_cblk(); + volatile display_cblk_t const * dcblk = cblk->displays + dpy; + + info->w = dcblk->w; + info->h = dcblk->h; + info->orientation = dcblk->orientation; + info->xdpi = dcblk->xdpi; + info->ydpi = dcblk->ydpi; + info->fps = dcblk->fps; + info->density = dcblk->density; + return getPixelFormatInfo(dcblk->format, &(info->pixelFormatInfo)); +} + +ssize_t SurfaceComposerClient::getDisplayWidth(DisplayID dpy) +{ + if (uint32_t(dpy)>=NUM_DISPLAY_MAX) + return BAD_VALUE; + volatile surface_flinger_cblk_t const * cblk = get_cblk(); + volatile display_cblk_t const * dcblk = cblk->displays + dpy; + return dcblk->w; +} + +ssize_t SurfaceComposerClient::getDisplayHeight(DisplayID dpy) +{ + if (uint32_t(dpy)>=NUM_DISPLAY_MAX) + return BAD_VALUE; + volatile surface_flinger_cblk_t const * cblk = get_cblk(); + volatile display_cblk_t const * dcblk = cblk->displays + dpy; + return dcblk->h; +} + +ssize_t SurfaceComposerClient::getDisplayOrientation(DisplayID dpy) +{ + if (uint32_t(dpy)>=NUM_DISPLAY_MAX) + return BAD_VALUE; + volatile surface_flinger_cblk_t const * cblk = get_cblk(); + volatile display_cblk_t const * dcblk = cblk->displays + dpy; + return dcblk->orientation; +} + +ssize_t SurfaceComposerClient::getNumberOfDisplays() +{ + volatile surface_flinger_cblk_t const * cblk = get_cblk(); + uint32_t connected = cblk->connected; + int n = 0; + while (connected) { + if (connected&1) n++; + connected >>= 1; + } + return n; +} + +sp<Surface> SurfaceComposerClient::createSurface( + int pid, + DisplayID display, + uint32_t w, + uint32_t h, + PixelFormat format, + uint32_t flags) +{ + sp<Surface> result; + if (mStatus == NO_ERROR) { + ISurfaceFlingerClient::surface_data_t data; + sp<ISurface> surface = mClient->createSurface(&data, pid, + display, w, h, format, flags); + if (surface != 0) { + if (uint32_t(data.token) < NUM_LAYERS_MAX) { + result = new Surface(this, surface, data, w, h, format, flags); + } + } + } + return result; +} + +status_t SurfaceComposerClient::destroySurface(SurfaceID sid) +{ + if (mStatus != NO_ERROR) + return mStatus; + + // it's okay to destroy a surface while a transaction is open, + // (transactions really are a client-side concept) + // however, this indicates probably a misuse of the API or a bug + // in the client code. + LOGW_IF(mTransactionOpen, + "Destroying surface while a transaction is open. " + "Client %p: destroying surface %d, mTransactionOpen=%d", + this, sid, mTransactionOpen); + + status_t err = mClient->destroySurface(sid); + return err; +} + +status_t SurfaceComposerClient::nextBuffer(Surface* surface, + Surface::SurfaceInfo* info) +{ + SurfaceID index = surface->ID(); + per_client_cblk_t* const cblk = mControl; + status_t err = validateSurface(cblk, surface); + if (err != NO_ERROR) + return err; + + int32_t backIdx = surface->mBackbufferIndex; + layer_cblk_t* const lcblk = &(cblk->layers[index]); + const surface_info_t* const front = lcblk->surface + (1-backIdx); + info->w = front->w; + info->h = front->h; + info->format = front->format; + info->base = surface->heapBase(1-backIdx); + info->bits = reinterpret_cast<void*>(intptr_t(info->base) + front->bits_offset); + info->bpr = front->bpr; + + return 0; +} + +status_t SurfaceComposerClient::lockSurface( + Surface* surface, + Surface::SurfaceInfo* other, + Region* dirty, + bool blocking) +{ + Mutex::Autolock _l(surface->getLock()); + + SurfaceID index = surface->ID(); + per_client_cblk_t* const cblk = mControl; + status_t err = validateSurface(cblk, surface); + if (err != NO_ERROR) + return err; + + int32_t backIdx = cblk->lock_layer(size_t(index), + per_client_cblk_t::BLOCKING); + if (backIdx >= 0) { + surface->mBackbufferIndex = backIdx; + layer_cblk_t* const lcblk = &(cblk->layers[index]); + const surface_info_t* const back = lcblk->surface + backIdx; + const surface_info_t* const front = lcblk->surface + (1-backIdx); + other->w = back->w; + other->h = back->h; + other->format = back->format; + other->base = surface->heapBase(backIdx); + other->bits = reinterpret_cast<void*>(intptr_t(other->base) + back->bits_offset); + other->bpr = back->bpr; + + const Rect bounds(other->w, other->h); + Region newDirtyRegion; + + if (back->flags & surface_info_t::eBufferDirty) { + /* it is safe to write *back here, because we're guaranteed + * SurfaceFlinger is not touching it (since it just granted + * access to us) */ + const_cast<surface_info_t*>(back)->flags &= + ~surface_info_t::eBufferDirty; + + // content is meaningless in this case and the whole surface + // needs to be redrawn. + + newDirtyRegion.set(bounds); + if (dirty) { + *dirty = newDirtyRegion; + } + + //if (bytesPerPixel(other->format) == 4) { + // android_memset32( + // (uint32_t*)other->bits, 0xFF00FF00, other->h * other->bpr); + //} else { + // android_memset16( // fill with green + // (uint16_t*)other->bits, 0x7E0, other->h * other->bpr); + //} + } + else + { + if (dirty) { + dirty->andSelf(Region(bounds)); + newDirtyRegion = *dirty; + } else { + newDirtyRegion.set(bounds); + } + + Region copyback; + if (!(lcblk->flags & eNoCopyBack)) { + const Region previousDirtyRegion(surface->dirtyRegion()); + copyback = previousDirtyRegion.subtract(newDirtyRegion); + } + + if (!copyback.isEmpty()) { + // copy front to back + GGLSurface cb; + cb.version = sizeof(GGLSurface); + cb.width = back->w; + cb.height = back->h; + cb.stride = back->stride; + cb.data = (GGLubyte*)surface->heapBase(backIdx); + cb.data += back->bits_offset; + cb.format = back->format; + + GGLSurface t; + t.version = sizeof(GGLSurface); + t.width = front->w; + t.height = front->h; + t.stride = front->stride; + t.data = (GGLubyte*)surface->heapBase(1-backIdx); + t.data += front->bits_offset; + t.format = front->format; + + //const Region copyback(lcblk->region + 1-backIdx); + copyBlt(cb, t, copyback); + } + } + + // update dirty region + surface->setDirtyRegion(newDirtyRegion); + } + return (backIdx < 0) ? status_t(backIdx) : status_t(NO_ERROR); +} + +void SurfaceComposerClient::_signal_server() +{ + mSignalServer->signal(); +} + +void SurfaceComposerClient::_send_dirty_region( + layer_cblk_t* lcblk, const Region& dirty) +{ + const int32_t index = (lcblk->flags & eBufferIndex) >> eBufferIndexShift; + flat_region_t* flat_region = lcblk->region + index; + status_t err = dirty.write(flat_region, sizeof(flat_region_t)); + if (err < NO_ERROR) { + // region doesn't fit, use the bounds + const Region reg(dirty.bounds()); + reg.write(flat_region, sizeof(flat_region_t)); + } +} + +status_t SurfaceComposerClient::unlockAndPostSurface(Surface* surface) +{ + Mutex::Autolock _l(surface->getLock()); + + SurfaceID index = surface->ID(); + per_client_cblk_t* const cblk = mControl; + status_t err = validateSurface(cblk, surface); + if (err != NO_ERROR) + return err; + + Region dirty(surface->dirtyRegion()); + const Rect& swapRect(surface->swapRectangle()); + if (swapRect.isValid()) { + dirty.set(swapRect); + } + + // transmit the dirty region + layer_cblk_t* const lcblk = &(cblk->layers[index]); + _send_dirty_region(lcblk, dirty); + uint32_t newstate = cblk->unlock_layer_and_post(size_t(index)); + if (!(newstate & eNextFlipPending)) + _signal_server(); + return NO_ERROR; +} + +status_t SurfaceComposerClient::unlockSurface(Surface* surface) +{ + Mutex::Autolock _l(surface->getLock()); + + SurfaceID index = surface->ID(); + per_client_cblk_t* const cblk = mControl; + status_t err = validateSurface(cblk, surface); + if (err != NO_ERROR) + return err; + + layer_cblk_t* const lcblk = &(cblk->layers[index]); + cblk->unlock_layer(size_t(index)); + return NO_ERROR; +} + +void SurfaceComposerClient::openGlobalTransaction() +{ + Mutex::Autolock _l(gLock); + + if (gOpenTransactions.size()) { + LOGE("openGlobalTransaction() called more than once. skipping."); + return; + } + + const size_t N = gActiveConnections.size(); + VERBOSE("openGlobalTransaction (%ld clients)", N); + for (size_t i=0; i<N; i++) { + sp<SurfaceComposerClient> client(gActiveConnections.valueAt(i)); + if (gOpenTransactions.indexOf(client) < 0) { + if (client->openTransaction() == NO_ERROR) { + if (gOpenTransactions.add(client) < 0) { + // Ooops! + LOGE( "Unable to add a SurfaceComposerClient " + "to the global transaction set (out of memory?)"); + client->closeTransaction(); + // let it go, it'll fail later when the user + // tries to do something with the transaction + } + } else { + LOGE("openTransaction on client %p failed", client.get()); + // let it go, it'll fail later when the user + // tries to do something with the transaction + } + } + } +} + +void SurfaceComposerClient::closeGlobalTransaction() +{ + gLock.lock(); + SortedVector< sp<SurfaceComposerClient> > clients(gOpenTransactions); + gOpenTransactions.clear(); + gLock.unlock(); + + const size_t N = clients.size(); + VERBOSE("closeGlobalTransaction (%ld clients)", N); + if (N == 1) { + clients[0]->closeTransaction(); + } else { + const sp<ISurfaceComposer>& sm(_get_surface_manager()); + sm->openGlobalTransaction(); + for (size_t i=0; i<N; i++) { + clients[i]->closeTransaction(); + } + sm->closeGlobalTransaction(); + } +} + +status_t SurfaceComposerClient::freezeDisplay(DisplayID dpy, uint32_t flags) +{ + const sp<ISurfaceComposer>& sm(_get_surface_manager()); + return sm->freezeDisplay(dpy, flags); +} + +status_t SurfaceComposerClient::unfreezeDisplay(DisplayID dpy, uint32_t flags) +{ + const sp<ISurfaceComposer>& sm(_get_surface_manager()); + return sm->unfreezeDisplay(dpy, flags); +} + +int SurfaceComposerClient::setOrientation(DisplayID dpy, int orientation) +{ + const sp<ISurfaceComposer>& sm(_get_surface_manager()); + return sm->setOrientation(dpy, orientation); +} + +status_t SurfaceComposerClient::openTransaction() +{ + if (mStatus != NO_ERROR) + return mStatus; + Mutex::Autolock _l(mLock); + VERBOSE( "openTransaction (client %p, mTransactionOpen=%d)", + this, mTransactionOpen); + mTransactionOpen++; + if (mPrebuiltLayerState == 0) { + mPrebuiltLayerState = new layer_state_t; + } + return NO_ERROR; +} + + +status_t SurfaceComposerClient::closeTransaction() +{ + if (mStatus != NO_ERROR) + return mStatus; + + Mutex::Autolock _l(mLock); + + VERBOSE( "closeTransaction (client %p, mTransactionOpen=%d)", + this, mTransactionOpen); + + if (mTransactionOpen <= 0) { + LOGE( "closeTransaction (client %p, mTransactionOpen=%d) " + "called more times than openTransaction()", + this, mTransactionOpen); + return INVALID_OPERATION; + } + + if (mTransactionOpen >= 2) { + mTransactionOpen--; + return NO_ERROR; + } + + mTransactionOpen = 0; + const ssize_t count = mStates.size(); + if (count) { + mClient->setState(count, mStates.array()); + mStates.clear(); + } + return NO_ERROR; +} + +layer_state_t* SurfaceComposerClient::_get_state_l(const sp<Surface>& surface) +{ + SurfaceID index = surface->ID(); + per_client_cblk_t* const cblk = mControl; + status_t err = validateSurface(cblk, surface.get()); + if (err != NO_ERROR) + return 0; + + // API usage error, do nothing. + if (mTransactionOpen<=0) { + LOGE("Not in transaction (client=%p, SurfaceID=%d, mTransactionOpen=%d", + this, int(index), mTransactionOpen); + return 0; + } + + // use mPrebuiltLayerState just to find out if we already have it + layer_state_t& dummy = *mPrebuiltLayerState; + dummy.surface = index; + ssize_t i = mStates.indexOf(dummy); + if (i < 0) { + // we don't have it, add an initialized layer_state to our list + i = mStates.add(dummy); + } + return mStates.editArray() + i; +} + +layer_state_t* SurfaceComposerClient::_lockLayerState(const sp<Surface>& surface) +{ + layer_state_t* s; + mLock.lock(); + s = _get_state_l(surface); + if (!s) mLock.unlock(); + return s; +} + +void SurfaceComposerClient::_unlockLayerState() +{ + mLock.unlock(); +} + +status_t SurfaceComposerClient::setPosition(Surface* surface, int32_t x, int32_t y) +{ + layer_state_t* s = _lockLayerState(surface); + if (!s) return BAD_INDEX; + s->what |= ISurfaceComposer::ePositionChanged; + s->x = x; + s->y = y; + _unlockLayerState(); + return NO_ERROR; +} + +status_t SurfaceComposerClient::setSize(Surface* surface, uint32_t w, uint32_t h) +{ + layer_state_t* s = _lockLayerState(surface); + if (!s) return BAD_INDEX; + s->what |= ISurfaceComposer::eSizeChanged; + s->w = w; + s->h = h; + _unlockLayerState(); + return NO_ERROR; +} + +status_t SurfaceComposerClient::setLayer(Surface* surface, int32_t z) +{ + layer_state_t* s = _lockLayerState(surface); + if (!s) return BAD_INDEX; + s->what |= ISurfaceComposer::eLayerChanged; + s->z = z; + _unlockLayerState(); + return NO_ERROR; +} + +status_t SurfaceComposerClient::hide(Surface* surface) +{ + return setFlags(surface, ISurfaceComposer::eLayerHidden, + ISurfaceComposer::eLayerHidden); +} + +status_t SurfaceComposerClient::show(Surface* surface, int32_t) +{ + return setFlags(surface, 0, ISurfaceComposer::eLayerHidden); +} + +status_t SurfaceComposerClient::freeze(Surface* surface) +{ + return setFlags(surface, ISurfaceComposer::eLayerFrozen, + ISurfaceComposer::eLayerFrozen); +} + +status_t SurfaceComposerClient::unfreeze(Surface* surface) +{ + return setFlags(surface, 0, ISurfaceComposer::eLayerFrozen); +} + +status_t SurfaceComposerClient::setFlags(Surface* surface, + uint32_t flags, uint32_t mask) +{ + layer_state_t* s = _lockLayerState(surface); + if (!s) return BAD_INDEX; + s->what |= ISurfaceComposer::eVisibilityChanged; + s->flags &= ~mask; + s->flags |= (flags & mask); + s->mask |= mask; + _unlockLayerState(); + return NO_ERROR; +} + + +status_t SurfaceComposerClient::setTransparentRegionHint( + Surface* surface, const Region& transparentRegion) +{ + layer_state_t* s = _lockLayerState(surface); + if (!s) return BAD_INDEX; + s->what |= ISurfaceComposer::eTransparentRegionChanged; + s->transparentRegion = transparentRegion; + _unlockLayerState(); + return NO_ERROR; +} + +status_t SurfaceComposerClient::setAlpha(Surface* surface, float alpha) +{ + layer_state_t* s = _lockLayerState(surface); + if (!s) return BAD_INDEX; + s->what |= ISurfaceComposer::eAlphaChanged; + s->alpha = alpha; + _unlockLayerState(); + return NO_ERROR; +} + +status_t SurfaceComposerClient::setMatrix( + Surface* surface, + float dsdx, float dtdx, + float dsdy, float dtdy ) +{ + layer_state_t* s = _lockLayerState(surface); + if (!s) return BAD_INDEX; + s->what |= ISurfaceComposer::eMatrixChanged; + layer_state_t::matrix22_t matrix; + matrix.dsdx = dsdx; + matrix.dtdx = dtdx; + matrix.dsdy = dsdy; + matrix.dtdy = dtdy; + s->matrix = matrix; + _unlockLayerState(); + return NO_ERROR; +} + +status_t SurfaceComposerClient::setFreezeTint(Surface* surface, uint32_t tint) +{ + layer_state_t* s = _lockLayerState(surface); + if (!s) return BAD_INDEX; + s->what |= ISurfaceComposer::eFreezeTintChanged; + s->tint = tint; + _unlockLayerState(); + return NO_ERROR; +} + +}; // namespace android + diff --git a/libs/ui/SurfaceFlingerSynchro.cpp b/libs/ui/SurfaceFlingerSynchro.cpp new file mode 100644 index 0000000..5cd9755 --- /dev/null +++ b/libs/ui/SurfaceFlingerSynchro.cpp @@ -0,0 +1,123 @@ +/* + * 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 "SurfaceFlingerSynchro" + +#include <stdint.h> +#include <string.h> +#include <unistd.h> +#include <fcntl.h> +#include <errno.h> +#include <limits.h> +#include <sys/types.h> +#include <sys/stat.h> + +#include <utils/IPCThreadState.h> +#include <utils/Log.h> + +#include <private/ui/SurfaceFlingerSynchro.h> + +namespace android { + +// --------------------------------------------------------------------------- + +SurfaceFlingerSynchro::Barrier::Barrier() + : state(CLOSED) { +} + +SurfaceFlingerSynchro::Barrier::~Barrier() { +} + +void SurfaceFlingerSynchro::Barrier::open() { + asm volatile ("":::"memory"); + Mutex::Autolock _l(lock); + state = OPENED; + cv.broadcast(); +} + +void SurfaceFlingerSynchro::Barrier::close() { + Mutex::Autolock _l(lock); + state = CLOSED; +} + +void SurfaceFlingerSynchro::Barrier::waitAndClose() +{ + Mutex::Autolock _l(lock); + while (state == CLOSED) { + // we're about to wait, flush the binder command buffer + IPCThreadState::self()->flushCommands(); + cv.wait(lock); + } + state = CLOSED; +} + +status_t SurfaceFlingerSynchro::Barrier::waitAndClose(nsecs_t timeout) +{ + Mutex::Autolock _l(lock); + while (state == CLOSED) { + // we're about to wait, flush the binder command buffer + IPCThreadState::self()->flushCommands(); + int err = cv.waitRelative(lock, timeout); + if (err != 0) + return err; + } + state = CLOSED; + return NO_ERROR; +} + +// --------------------------------------------------------------------------- + +SurfaceFlingerSynchro::SurfaceFlingerSynchro(const sp<ISurfaceComposer>& flinger) + : mSurfaceComposer(flinger) +{ +} + +SurfaceFlingerSynchro::SurfaceFlingerSynchro() +{ +} + +SurfaceFlingerSynchro::~SurfaceFlingerSynchro() +{ +} + +status_t SurfaceFlingerSynchro::signal() +{ + mSurfaceComposer->signal(); + return NO_ERROR; +} + +status_t SurfaceFlingerSynchro::wait() +{ + mBarrier.waitAndClose(); + return NO_ERROR; +} + +status_t SurfaceFlingerSynchro::wait(nsecs_t timeout) +{ + if (timeout == 0) + return SurfaceFlingerSynchro::wait(); + return mBarrier.waitAndClose(timeout); +} + +void SurfaceFlingerSynchro::open() +{ + mBarrier.open(); +} + +// --------------------------------------------------------------------------- + +}; // namespace android + diff --git a/libs/ui/Time.cpp b/libs/ui/Time.cpp new file mode 100644 index 0000000..c98667f --- /dev/null +++ b/libs/ui/Time.cpp @@ -0,0 +1,199 @@ +#include <utils/TimeUtils.h> +#include <stdio.h> +#include <cutils/tztime.h> + +namespace android { + +static void +dump(const Time& t) +{ + #ifdef HAVE_TM_GMTOFF + long tm_gmtoff = t.t.tm_gmtoff; + #else + long tm_gmtoff = 0; + #endif + printf("%04d-%02d-%02d %02d:%02d:%02d (%d,%ld,%d,%d)\n", + t.t.tm_year+1900, t.t.tm_mon+1, t.t.tm_mday, + t.t.tm_hour, t.t.tm_min, t.t.tm_sec, + t.t.tm_isdst, tm_gmtoff, t.t.tm_wday, t.t.tm_yday); +} + +Time::Time() +{ + t.tm_sec = 0; + t.tm_min = 0; + t.tm_hour = 0; + t.tm_mday = 0; + t.tm_mon = 0; + t.tm_year = 0; + t.tm_wday = 0; + t.tm_yday = 0; + t.tm_isdst = -1; // we don't know, so let the C library determine + #ifdef HAVE_TM_GMTOFF + t.tm_gmtoff = 0; + #endif +} + + +#define COMPARE_FIELD(field) do { \ + int diff = a.t.field - b.t.field; \ + if (diff != 0) return diff; \ + } while(0) + +int +Time::compare(Time& a, Time& b) +{ + if (0 == strcmp(a.timezone, b.timezone)) { + // if the timezones are the same, we can easily compare the two + // times. Otherwise, convert to milliseconds and compare that. + // This requires that object be normalized. + COMPARE_FIELD(tm_year); + COMPARE_FIELD(tm_mon); + COMPARE_FIELD(tm_mday); + COMPARE_FIELD(tm_hour); + COMPARE_FIELD(tm_min); + COMPARE_FIELD(tm_sec); + return 0; + } else { + int64_t am = a.toMillis(false /* use isDst */); + int64_t bm = b.toMillis(false /* use isDst */); + int64_t diff = am-bm; + return (diff < 0) ? -1 : ((diff > 0) ? 1 : 0); + } +} + +static const int DAYS_PER_MONTH[] = { + 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 + }; + +static inline int days_this_month(int year, int month) +{ + int n = DAYS_PER_MONTH[month]; + if (n != 28) { + return n; + } else { + int y = year; + return ((y%4)==0&&((y%100)!=0||(y%400)==0)) ? 29 : 28; + } +} + +void +Time::switchTimezone(const char* timezone) +{ + time_t seconds = mktime_tz(&(this->t), this->timezone); + localtime_tz(&seconds, &(this->t), timezone); +} + +String8 +Time::format(const char *format) const +{ + char buf[257]; + int n = strftime(buf, 257, format, &(this->t)); + if (n > 0) { + return String8(buf); + } else { + return String8(); + } +} + +static inline short +tochar(int n) +{ + return (n >= 0 && n <= 9) ? ('0'+n) : ' '; +} + +static inline short +next_char(int *m, int k) +{ + int n = *m / k; + *m = *m % k; + return tochar(n); +} + +void +Time::format2445(short* buf, bool hasTime) const +{ + int n; + + n = t.tm_year+1900; + buf[0] = next_char(&n, 1000); + buf[1] = next_char(&n, 100); + buf[2] = next_char(&n, 10); + buf[3] = tochar(n); + + n = t.tm_mon+1; + buf[4] = next_char(&n, 10); + buf[5] = tochar(n); + + n = t.tm_mday; + buf[6] = next_char(&n, 10); + buf[7] = tochar(n); + + if (hasTime) { + buf[8] = 'T'; + + n = t.tm_hour; + buf[9] = next_char(&n, 10); + buf[10] = tochar(n); + + n = t.tm_min; + buf[11] = next_char(&n, 10); + buf[12] = tochar(n); + + n = t.tm_sec; + buf[13] = next_char(&n, 10); + buf[14] = tochar(n); + bool inUtc = strcmp("UTC", timezone) == 0; + if (inUtc) { + buf[15] = 'Z'; + } + } +} + +String8 +Time::toString() const +{ + String8 str; + char* s = str.lockBuffer(150); + #ifdef HAVE_TM_GMTOFF + long tm_gmtoff = t.tm_gmtoff; + #else + long tm_gmtoff = 0; + #endif + sprintf(s, "%04d%02d%02dT%02d%02d%02d%s(%d,%d,%ld,%d,%d)", + t.tm_year+1900, t.tm_mon+1, t.tm_mday, t.tm_hour, t.tm_min, + t.tm_sec, timezone, t.tm_wday, t.tm_yday, tm_gmtoff, t.tm_isdst, + (int)(((Time*)this)->toMillis(false /* use isDst */)/1000)); + str.unlockBuffer(); + return str; +} + +void +Time::setToNow() +{ + time_t seconds; + time(&seconds); + localtime_tz(&seconds, &(this->t), this->timezone); +} + +int64_t +Time::toMillis(bool ignoreDst) +{ + if (ignoreDst) { + this->t.tm_isdst = -1; + } + int64_t r = mktime_tz(&(this->t), this->timezone); + if (r == -1) + return -1; + return r * 1000; +} + +void +Time::set(int64_t millis) +{ + time_t seconds = millis / 1000; + localtime_tz(&seconds, &(this->t), this->timezone); +} + +}; // namespace android + |