summaryrefslogtreecommitdiffstats
path: root/libs/ui
diff options
context:
space:
mode:
authorThe Android Open Source Project <initial-contribution@android.com>2008-10-21 07:00:00 -0700
committerThe Android Open Source Project <initial-contribution@android.com>2008-10-21 07:00:00 -0700
commit54b6cfa9a9e5b861a9930af873580d6dc20f773c (patch)
tree35051494d2af230dce54d6b31c6af8fc24091316 /libs/ui
downloadframeworks_base-54b6cfa9a9e5b861a9930af873580d6dc20f773c.zip
frameworks_base-54b6cfa9a9e5b861a9930af873580d6dc20f773c.tar.gz
frameworks_base-54b6cfa9a9e5b861a9930af873580d6dc20f773c.tar.bz2
Initial Contribution
Diffstat (limited to 'libs/ui')
-rw-r--r--libs/ui/Android.mk39
-rw-r--r--libs/ui/BlitHardware.cpp446
-rw-r--r--libs/ui/Camera.cpp249
-rw-r--r--libs/ui/CameraParameters.cpp253
-rw-r--r--libs/ui/EGLDisplaySurface.cpp471
-rw-r--r--libs/ui/EGLNativeWindowSurface.cpp181
-rw-r--r--libs/ui/EventHub.cpp743
-rw-r--r--libs/ui/EventRecurrence.cpp484
-rw-r--r--libs/ui/ICamera.cpp204
-rw-r--r--libs/ui/ICameraClient.cpp153
-rw-r--r--libs/ui/ICameraService.cpp77
-rw-r--r--libs/ui/ISurface.cpp117
-rw-r--r--libs/ui/ISurfaceComposer.cpp277
-rw-r--r--libs/ui/ISurfaceFlingerClient.cpp210
-rw-r--r--libs/ui/KeyCharacterMap.cpp263
-rw-r--r--libs/ui/KeyLayoutMap.cpp235
-rw-r--r--libs/ui/KeyLayoutMap.h31
-rw-r--r--libs/ui/LayerState.cpp53
-rw-r--r--libs/ui/MODULE_LICENSE_APACHE20
-rw-r--r--libs/ui/NOTICE190
-rw-r--r--libs/ui/PixelFormat.cpp66
-rw-r--r--libs/ui/Point.cpp11
-rw-r--r--libs/ui/Rect.cpp86
-rw-r--r--libs/ui/Region.cpp315
-rw-r--r--libs/ui/Surface.cpp261
-rw-r--r--libs/ui/SurfaceComposerClient.cpp1026
-rw-r--r--libs/ui/SurfaceFlingerSynchro.cpp123
-rw-r--r--libs/ui/Time.cpp199
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 &params)
+{
+ 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(&params, 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
+