Пример #1
0
bool LayerScreenshot::isFrozen() {
    Mutex::Autolock _l(gLock);

    int count = gLayerStatus.size();
    if (count <= 0) return false;

    LayerStatus top = gLayerStatus.valueAt(0);
    int identity = gLayerStatus.keyAt(0);
    for (int i = 1; i < count; i++) {
        LayerStatus state = gLayerStatus.valueAt(i);
        if (state.z > top.z) {
            top = state;
            identity = gLayerStatus.keyAt(i);
        }
    }

    XLOGI("[%s] LayerScreenshot top:%d (orient:%d, alpha:%d)",
        __func__, identity, top.orient, top.alpha);

    if ((top.orient & Transform::ROT_INVALID) || (0xff > top.alpha)) {
        XLOGI("    No need to freeze screen...");
        return false;
    }

    XLOGD("    Freeze screen...");
    return true;
}
Пример #2
0
/**
 * Activate/deactivate a given sensor
 *
 * @param sensorType - Type of the sensor to activate/deactivate
 * @param activate - 1 to activate and 0 to deactivate the sensor
 * @param rate - sampling rate in microseconds
 */
int SensorsCommand::sensors_activate(int sensorType, int activate, int rate) {
  // Get sensor device handle given the sensor type
  int count;
  for (count = 0; count < mSensorListCount; count++) {
    if (mSensorsList[count].type == sensorType) {
      break;
    }
  }
  LOG_ERROR((count >= mSensorListCount), "No such h/w sensor available %d",
      sensorType);

  int err;
  Value jsonMsg;
  if (activate) {
    // Only activate if not already active
    if (!mActiveSensors.valueFor(mSensorsList[count].handle)) {
      err = mDevice->activate(
          reinterpret_cast<struct sensors_poll_device_t *>(mDevice),
          mSensorsList[count].handle, 1);
      LOG_ERROR((err != 0), "Failed to activate the sensor");

      if (mDevice->common.version >= SENSORS_DEVICE_API_VERSION_1_1) {
        mDevice->batch(mDevice, mSensorsList[count].handle, 0, ms2ns(rate),
            ms2ns(rate));
      } else {
        mDevice->setDelay(
            reinterpret_cast<struct sensors_poll_device_t *>(mDevice),
            mSensorsList[count].handle, ms2ns(rate));
      }
      mActiveSensorCount++;
      mActiveSensors.add(mSensorsList[count].handle, true);
    }
    jsonMsg["eventName"] = "activated";
    mSensorsListener->sendEvent(jsonMsg);
  } else  {
    if (mActiveSensors.valueFor(mSensorsList[count].handle)) {
      mActiveSensorCount--;
      mActiveSensors.removeItem(mSensorsList[count].handle);

      // If no more active sensors then stop polling
      if (mActiveSensorCount <= 0) {
        mSensorsPoll->stop();
        mSensorsPoll = NULL;
      }

      err = mDevice->activate(
          reinterpret_cast<struct sensors_poll_device_t *>(mDevice),
          mSensorsList[count].handle, 0);
      LOG_ERROR((err != 0), "Failed to deactivate the sensor");
    }

    jsonMsg["eventName"] = "deactivated";
    mSensorsListener->sendEvent(jsonMsg);
  }
  return 0;
}
void MCameraClient::notifyCallback(int32_t msgType, int32_t ext1, int32_t ext2) {
    INFO("%s", __func__);
    Mutex::Autolock _l(mLock);
    ssize_t i = mNotifyCount.indexOfKey(msgType);
    if (i < 0) {
        mNotifyCount.add(msgType, 1);
    } else {
        ++mNotifyCount.editValueAt(i);
    }
    mCond.signal();
}
Пример #4
0
void LayerScreenshot::clearStatus() {
    Mutex::Autolock _l(gLock);
    for (uint32_t i = 0; i < gLayerStatus.size(); i++) {
        int identity = gLayerStatus.keyAt(i);
        if (this->getIdentity() == (uint32_t)identity) {
            gLayerStatus.removeItem(identity);
            XLOGI("[%s] del:%d, count:%d", __func__,
                identity, gLayerStatus.size());
            break;
        }
    }
}
void RemoteCallbackList::finishBroadcast() {
    Mutex::Autolock _l(_mutex);

	DefaultKeyedVector< wp<IBinder>, sp<RemoteCallback> >* pActiveCBs =_activeCBsList.valueFor(pthread_self());
	if(pActiveCBs == NULL) {
        ALOGW("%s called outside of a broadcast",__FUNCTION__);
        return;
	}

	pActiveCBs->clear();
	_activeCBsList.removeItem(pthread_self());

	delete pActiveCBs;
	pActiveCBs = NULL;
}
Пример #6
0
void GPUHardware::binderDied(const wp<IBinder>& who)
{
    Mutex::Autolock _l(mLock);
    pid_t pid = mRegisteredClients.valueFor(who);
    if (pid != 0) {
        ssize_t index = mClients.indexOfKey(pid);
        if (index >= 0) {
            //LOGD("*** removing client at %d", index);
            Client& client(mClients.editValueAt(index));
            client.revokeAllHeaps(); // not really needed in theory
            mClients.removeItemsAt(index);
            if (mClients.size() == 0) {
                //LOGD("*** was last client closing everything");
                mCallback.clear();
                mAllocator.clear();
                mCurrentAllocator.clear();
                mSMIHeap.clear();
                mREGHeap.clear();
                
                // NOTE: we cannot clear the EBI heap because surfaceflinger
                // itself may be using it, since this is where surfaces
                // are allocated. if we're in the middle of compositing 
                // a surface (even if its process just died), we cannot
                // rip the heap under our feet.
                
                mOwner = NO_OWNER;
            }
        }
    }
}
Пример #7
0
GuiExtPoolItem::GuiExtPoolItem(const sp<IBinder>& token,
                bool isHwcNeeded,
                uint32_t poolId,
                uint32_t /*w*/,
                uint32_t /*h*/,
                DefaultKeyedVector< uint32_t, sp<DispInfo> >& dispList,
                sp<IBinder::DeathRecipient> observer)
                : mConsumerDeathListener(NULL)
                //, mGPUUsedBq(NULL)
                , mGPUUsedProducer(NULL)
                , mGPUUsedConsumer(NULL)
#if !SUPPORT_MULTIBQ_FOR_HWC
                , mHwcUsedBq(NULL)
#endif
                , mId(poolId)
                , mIsHwcNeeded(isHwcNeeded)
                , mGpuUsedBufNum(MAX_GLES_DEQUEUED_NUM)
                , mProducerPid(-1)
                , mProducerToken(token)
                , mProducerDeathObserver(observer)

{
    GUIEXT_LOGV("GuiExtPoolItem ctor, poolId=%d, isHwcNeeded=%d, token=%p", poolId, isHwcNeeded, token.get());

    //String8 name(szUsageName[0]);
    //name.appendFormat("_%d", poolId);
    //mGPUUsedBq = createBufferQueue(w, h, mGpuUsedBufNum, name);
    //createBufferQueue(w, h, mGpuUsedBufNum, name, &mGPUUsedProducer, &mGPUUsedConsumer);

#ifdef CONFIG_FOR_SOURCE_PQ
    setOverlaySessionMode(true);
#endif
    if (mIsHwcNeeded) {
        String8 name(szUsageName[1]);
        name.appendFormat("_%d", poolId);
#if SUPPORT_MULTIBQ_FOR_HWC
        uint32_t disp_size = dispList.size();
        for (uint32_t i = 0; i < disp_size; i++) {
            uint32_t type = dispList[i]->type;
            String8 extname(name);
            extname.appendFormat("_%d", type);
            sp<HwcBqSlot> slot = new HwcBqSlot();
            //slot->bq = createBufferQueue(dispList[i]->w, dispList[i]->h, dispList[i]->bufNum, extname);
            createBufferQueue(dispList[i]->w, dispList[i]->h, dispList[i]->bufNum, extname, &slot->mProducer, &slot->mConsumer);
            slot->type = type;
            slot->bufNum = dispList[i]->bufNum;
            mHwcUsedBqList.add(type, slot);
        }
#else
        mHwcUsedBq = createBufferQueue(dispList[0]->w, dispList[0]->h, dispList[i]->bufNum, name);
#endif
    }

    mProducerPid = (NULL != token->localBinder())
                 ? getpid()
                 : IPCThreadState::self()->getCallingPid();

    for (uint32_t i = 0; i < GUI_EXT_USAGE_MAX; i++)
        mIsDisconnected[i] = true;
}
Пример #8
0
void GPUHardware::registerCallbackLocked(const sp<IGPUCallback>& callback,
        Client& client)
{
    sp<IBinder> binder = callback->asBinder();
    if (mRegisteredClients.add(binder, client.pid) >= 0) {
        binder->linkToDeath(this);
    }
}
void* RemoteCallbackList::getBroadcastCookie(int index) {
    Mutex::Autolock _l(_mutex);
	
	DefaultKeyedVector< wp<IBinder>, sp<RemoteCallback> >* pActiveCBs =_activeCBsList.valueFor(pthread_self());

	if (pActiveCBs == NULL || pActiveCBs->size() <= 0){
		ALOGE("%s activeCBs null\n",__FUNCTION__);
		return NULL;
	}

    int size = pActiveCBs->size();
    if(index >= 0 && index < size && pActiveCBs->valueAt(index)!= NULL) {
        return pActiveCBs->valueAt(index)->_cookie;
    }

    ALOGW("%s out of border",__FUNCTION__);
    return NULL;
}
void MCameraClient::waitData(int32_t msgType, OP op, int count) {
    INFO("waitData: %d, %d, %d", msgType, op, count);
    Mutex::Autolock _l(mLock);
    while (true) {
        int v = mDataCount.valueFor(msgType);
        if (test(op, v, count)) {
            break;
        }
        mCond.wait(mLock);
    }
}
void MCameraClient::dataCallback(int32_t msgType, const sp<IMemory>& data) {
    INFO("%s", __func__);
    int dataSize = data->size();
    INFO("data type = %d, size = %d", msgType, dataSize);
    Mutex::Autolock _l(mLock);
    ssize_t i = mDataCount.indexOfKey(msgType);
    if (i < 0) {
        mDataCount.add(msgType, 1);
        mDataSize.add(msgType, dataSize);
    } else {
        ++mDataCount.editValueAt(i);
        mDataSize.editValueAt(i) = dataSize;
    }
    mCond.signal();

    if (msgType == CAMERA_MSG_VIDEO_FRAME) {
        ASSERT(mReleaser != NULL);
        mReleaser->releaseRecordingFrame(data);
    }
}
Пример #12
0
void LayerScreenshot::setGeometry(const sp<const DisplayDevice>& hw,
        HWComposer::HWCLayerInterface& layer)
{
    LayerBaseClient::setGeometry(hw, layer);

    Mutex::Autolock _l(gLock);

    LayerStatus state;

    const LayerBase::State& s(drawingState());
    const Transform tr(hw->getTransform() * s.transform);
    state.z = s.z;
    state.alpha = s.alpha;
    state.orient = tr.getOrientation();

    gLayerStatus.add(this->getIdentity(), state);

    XLOGI("[%s] add:%d, count:%d", __func__,
        this->getIdentity(), gLayerStatus.size());
}
int RemoteCallbackList::beginBroadcast() {
    Mutex::Autolock _l(_mutex);
	
	DefaultKeyedVector< wp<IBinder>, sp<RemoteCallback> >* pActiveCBs = _activeCBsList.valueFor(pthread_self());
	if(pActiveCBs != NULL) {
        ALOGW("%s called while already in a broadcast\n",__FUNCTION__);
        return -1;
	}

	pActiveCBs = new DefaultKeyedVector< wp<IBinder>, sp<RemoteCallback> >;
	if(pActiveCBs == NULL) {
		ALOGW("[%s]out of memory\n",__FUNCTION__);
		return -2;
	}
	
    int size = _callbacks.size();
    for(int i=0;i<size;i++) {
        pActiveCBs->add(_callbacks.keyAt(i),_callbacks[i]);
    }
	_activeCBsList.add(pthread_self(),pActiveCBs);
    return size;
}
Пример #14
0
__eglMustCastToProperFunctionPointerType eglGetProcAddress(const char *procname)
{
    // eglGetProcAddress() could be the very first function called
    // in which case we must make sure we've initialized ourselves, this
    // happens the first time egl_get_display() is called.

    clearError();

    if (egl_init_drivers() == EGL_FALSE) {
        setError(EGL_BAD_PARAMETER, NULL);
        return  NULL;
    }

    // The EGL_ANDROID_blob_cache extension should not be exposed to
    // applications.  It is used internally by the Android EGL layer.
    if (!strcmp(procname, "eglSetBlobCacheFuncsANDROID")) {
        return NULL;
    }

    __eglMustCastToProperFunctionPointerType addr;
    addr = findProcAddress(procname, sExtentionMap, NELEM(sExtentionMap));
    if (addr) return addr;


    // this protects accesses to sGLExtentionMap and sGLExtentionSlot
    pthread_mutex_lock(&sExtensionMapMutex);

        /*
         * Since eglGetProcAddress() is not associated to anything, it needs
         * to return a function pointer that "works" regardless of what
         * the current context is.
         *
         * For this reason, we return a "forwarder", a small stub that takes
         * care of calling the function associated with the context
         * currently bound.
         *
         * We first look for extensions we've already resolved, if we're seeing
         * this extension for the first time, we go through all our
         * implementations and call eglGetProcAddress() and record the
         * result in the appropriate implementation hooks and return the
         * address of the forwarder corresponding to that hook set.
         *
         */

        const String8 name(procname);
        addr = sGLExtentionMap.valueFor(name);
        const int slot = sGLExtentionSlot;

        LOGE_IF(slot >= MAX_NUMBER_OF_GL_EXTENSIONS,
                "no more slots for eglGetProcAddress(\"%s\")",
                procname);

        if (!addr && (slot < MAX_NUMBER_OF_GL_EXTENSIONS)) {
            bool found = false;
            for (int i=0 ; i<IMPL_NUM_IMPLEMENTATIONS ; i++) {
                egl_connection_t* const cnx = &gEGLImpl[i];
                if (cnx->dso && cnx->egl.eglGetProcAddress) {
                    found = true;
                    // Extensions are independent of the bound context
                    cnx->hooks[GLESv1_INDEX]->ext.extensions[slot] =
                    cnx->hooks[GLESv2_INDEX]->ext.extensions[slot] =
#if EGL_TRACE
                    gHooksDebug.ext.extensions[slot] = gHooksTrace.ext.extensions[slot] =
#endif
                            cnx->egl.eglGetProcAddress(procname);
                }
            }
            if (found) {
                addr = gExtensionForwarders[slot];

                if (!strcmp(procname, "glEGLImageTargetTexture2DOES")) {
                    glEGLImageTargetTexture2DOES_impl = (PFNGLEGLIMAGETARGETTEXTURE2DOESPROC)addr;
                    addr = (__eglMustCastToProperFunctionPointerType)glEGLImageTargetTexture2DOES_wrapper;
                }
                if (!strcmp(procname, "glEGLImageTargetRenderbufferStorageOES")) {
                    glEGLImageTargetRenderbufferStorageOES_impl = (PFNGLEGLIMAGETARGETRENDERBUFFERSTORAGEOESPROC)addr;
                    addr = (__eglMustCastToProperFunctionPointerType)glEGLImageTargetRenderbufferStorageOES_wrapper;
                }

                sGLExtentionMap.add(name, addr);
                sGLExtentionSlot++;
            }
        }

    pthread_mutex_unlock(&sExtensionMapMutex);
    return addr;
}
Пример #15
0
void StringPool::sortByConfig()
{
    LOG_ALWAYS_FATAL_IF(mOriginalPosToNewPos.size() > 0, "Can't sort string pool after already sorted.");

    const size_t N = mEntryArray.size();

    // This is a vector that starts out with a 1:1 mapping to entries
    // in the array, which we will sort to come up with the desired order.
    // At that point it maps from the new position in the array to the
    // original position the entry appeared.
    Vector<size_t> newPosToOriginalPos;
    newPosToOriginalPos.setCapacity(N);
    for (size_t i=0; i < N; i++) {
        newPosToOriginalPos.add(i);
    }

    // Sort the array.
    NOISY(printf("SORTING STRINGS BY CONFIGURATION...\n"));
    // Vector::sort uses insertion sort, which is very slow for this data set.
    // Use quicksort instead because we don't need a stable sort here.
    qsort_r_compat(newPosToOriginalPos.editArray(), N, sizeof(size_t), this, config_sort);
    //newPosToOriginalPos.sort(config_sort, this);
    NOISY(printf("DONE SORTING STRINGS BY CONFIGURATION.\n"));

    // Create the reverse mapping from the original position in the array
    // to the new position where it appears in the sorted array.  This is
    // so that clients can re-map any positions they had previously stored.
    mOriginalPosToNewPos = newPosToOriginalPos;
    for (size_t i=0; i<N; i++) {
        mOriginalPosToNewPos.editItemAt(newPosToOriginalPos[i]) = i;
    }

#if 0
    SortedVector<entry> entries;

    for (size_t i=0; i<N; i++) {
        printf("#%d was %d: %s\n", i, newPosToOriginalPos[i],
                mEntries[mEntryArray[newPosToOriginalPos[i]]].makeConfigsString().string());
        entries.add(mEntries[mEntryArray[i]]);
    }

    for (size_t i=0; i<entries.size(); i++) {
        printf("Sorted config #%d: %s\n", i,
                entries[i].makeConfigsString().string());
    }
#endif

    // Now we rebuild the arrays.
    Vector<entry> newEntries;
    Vector<size_t> newEntryArray;
    Vector<entry_style> newEntryStyleArray;
    DefaultKeyedVector<size_t, size_t> origOffsetToNewOffset;

    for (size_t i=0; i<N; i++) {
        // We are filling in new offset 'i'; oldI is where we can find it
        // in the original data structure.
        size_t oldI = newPosToOriginalPos[i];
        // This is the actual entry associated with the old offset.
        const entry& oldEnt = mEntries[mEntryArray[oldI]];
        // This is the same entry the last time we added it to the
        // new entry array, if any.
        ssize_t newIndexOfOffset = origOffsetToNewOffset.indexOfKey(oldI);
        size_t newOffset;
        if (newIndexOfOffset < 0) {
            // This is the first time we have seen the entry, so add
            // it.
            newOffset = newEntries.add(oldEnt);
            newEntries.editItemAt(newOffset).indices.clear();
        } else {
            // We have seen this entry before, use the existing one
            // instead of adding it again.
            newOffset = origOffsetToNewOffset.valueAt(newIndexOfOffset);
        }
        // Update the indices to include this new position.
        newEntries.editItemAt(newOffset).indices.add(i);
        // And add the offset of the entry to the new entry array.
        newEntryArray.add(newOffset);
        // Add any old style to the new style array.
        if (mEntryStyleArray.size() > 0) {
            if (oldI < mEntryStyleArray.size()) {
                newEntryStyleArray.add(mEntryStyleArray[oldI]);
            } else {
                newEntryStyleArray.add(entry_style());
            }
        }
    }

    // Now trim any entries at the end of the new style array that are
    // not needed.
    for (ssize_t i=newEntryStyleArray.size()-1; i>=0; i--) {
        const entry_style& style = newEntryStyleArray[i];
        if (style.spans.size() > 0) {
            // That's it.
            break;
        }
        // This one is not needed; remove.
        newEntryStyleArray.removeAt(i);
    }

    // All done, install the new data structures and upate mValues with
    // the new positions.
    mEntries = newEntries;
    mEntryArray = newEntryArray;
    mEntryStyleArray = newEntryStyleArray;
    mValues.clear();
    for (size_t i=0; i<mEntries.size(); i++) {
        const entry& ent = mEntries[i];
        mValues.add(ent.value, ent.indices[0]);
    }

#if 0
    printf("FINAL SORTED STRING CONFIGS:\n");
    for (size_t i=0; i<mEntries.size(); i++) {
        const entry& ent = mEntries[i];
        printf("#" ZD " %s: %s\n", (ZD_TYPE)i, ent.makeConfigsString().string(),
                String8(ent.value).string());
    }
#endif
}
void MCameraClient::assertNotify(int32_t msgType, OP op, int count) {
    Mutex::Autolock _l(mLock);
    int v = mNotifyCount.valueFor(msgType);
    ASSERT(test(op, v, count));
}
void MCameraClient::assertDataSize(int32_t msgType, OP op, int dataSize) {
    Mutex::Autolock _l(mLock);
    int v = mDataSize.valueFor(msgType);
    assertTest(op, v, dataSize);
}
void MCameraClient::assertData(int32_t msgType, OP op, int count) {
    Mutex::Autolock _l(mLock);
    int v = mDataCount.valueFor(msgType);
    assertTest(op, v, count);
}
void MCameraClient::clearStat() {
    Mutex::Autolock _l(mLock);
    mNotifyCount.clear();
    mDataCount.clear();
    mDataSize.clear();
}
Пример #20
0
__eglMustCastToProperFunctionPointerType eglGetProcAddress(const char *procname)
{
    // eglGetProcAddress() could be the very first function called
    // in which case we must make sure we've initialized ourselves, this
    // happens the first time egl_get_display() is called.

    clearError();

    if (egl_init_drivers() == EGL_FALSE) {
        setError(EGL_BAD_PARAMETER, NULL);
        return  NULL;
    }

    // These extensions should not be exposed to applications. They're used
    // internally by the Android EGL layer.
    if (!strcmp(procname, "eglSetBlobCacheFuncsANDROID") ||
        !strcmp(procname, "eglDupNativeFenceFDANDROID") ||
        !strcmp(procname, "eglWaitSyncANDROID") ||
        !strcmp(procname, "eglHibernateProcessIMG") ||
        !strcmp(procname, "eglAwakenProcessIMG")) {
        return NULL;
    }

    __eglMustCastToProperFunctionPointerType addr;
    addr = findProcAddress(procname, sExtentionMap, NELEM(sExtentionMap));
    if (addr) return addr;


    // this protects accesses to sGLExtentionMap and sGLExtentionSlot
    pthread_mutex_lock(&sExtensionMapMutex);

        /*
         * Since eglGetProcAddress() is not associated to anything, it needs
         * to return a function pointer that "works" regardless of what
         * the current context is.
         *
         * For this reason, we return a "forwarder", a small stub that takes
         * care of calling the function associated with the context
         * currently bound.
         *
         * We first look for extensions we've already resolved, if we're seeing
         * this extension for the first time, we go through all our
         * implementations and call eglGetProcAddress() and record the
         * result in the appropriate implementation hooks and return the
         * address of the forwarder corresponding to that hook set.
         *
         */

        const String8 name(procname);
        addr = sGLExtentionMap.valueFor(name);
        const int slot = sGLExtentionSlot;

        ALOGE_IF(slot >= MAX_NUMBER_OF_GL_EXTENSIONS,
                "no more slots for eglGetProcAddress(\"%s\")",
                procname);

#if EGL_TRACE
        gl_hooks_t *debugHooks = GLTrace_getGLHooks();
#endif

        if (!addr && (slot < MAX_NUMBER_OF_GL_EXTENSIONS)) {
            bool found = false;

            egl_connection_t* const cnx = &gEGLImpl;
            if (cnx->dso && cnx->egl.eglGetProcAddress) {
                found = true;
                // Extensions are independent of the bound context
                cnx->hooks[egl_connection_t::GLESv1_INDEX]->ext.extensions[slot] =
                cnx->hooks[egl_connection_t::GLESv2_INDEX]->ext.extensions[slot] =
#if EGL_TRACE
                debugHooks->ext.extensions[slot] =
                gHooksTrace.ext.extensions[slot] =
#endif
                        cnx->egl.eglGetProcAddress(procname);
            }

            if (found) {
                addr = gExtensionForwarders[slot];
                sGLExtentionMap.add(name, addr);
                sGLExtentionSlot++;
            }
        }

    pthread_mutex_unlock(&sExtensionMapMutex);
    return addr;
}
Пример #21
0
int LayerScreenshot::getCount() {
    Mutex::Autolock _l(gLock);
    int count = gLayerStatus.size();
    return count;
}
Пример #22
0
namespace android {
// ---------------------------------------------------------------------------

struct LayerStatus {
    LayerStatus() : z(0), alpha(0xff), orient(Transform::ROT_0) { }
    uint32_t z;
    uint8_t alpha;
    int32_t orient;
};

DefaultKeyedVector<int, LayerStatus> gLayerStatus;
Mutex gLock;

void LayerScreenshot::setGeometry(const sp<const DisplayDevice>& hw,
        HWComposer::HWCLayerInterface& layer)
{
    LayerBaseClient::setGeometry(hw, layer);

    Mutex::Autolock _l(gLock);

    LayerStatus state;

    const LayerBase::State& s(drawingState());
    const Transform tr(hw->getTransform() * s.transform);
    state.z = s.z;
    state.alpha = s.alpha;
    state.orient = tr.getOrientation();

    gLayerStatus.add(this->getIdentity(), state);

    XLOGI("[%s] add:%d, count:%d", __func__,
        this->getIdentity(), gLayerStatus.size());
}

void LayerScreenshot::clearStatus() {
    Mutex::Autolock _l(gLock);
    for (uint32_t i = 0; i < gLayerStatus.size(); i++) {
        int identity = gLayerStatus.keyAt(i);
        if (this->getIdentity() == (uint32_t)identity) {
            gLayerStatus.removeItem(identity);
            XLOGI("[%s] del:%d, count:%d", __func__,
                identity, gLayerStatus.size());
            break;
        }
    }
}

int LayerScreenshot::getCount() {
    Mutex::Autolock _l(gLock);
    int count = gLayerStatus.size();
    return count;
}

bool LayerScreenshot::isFrozen() {
    Mutex::Autolock _l(gLock);

    int count = gLayerStatus.size();
    if (count <= 0) return false;

    LayerStatus top = gLayerStatus.valueAt(0);
    int identity = gLayerStatus.keyAt(0);
    for (int i = 1; i < count; i++) {
        LayerStatus state = gLayerStatus.valueAt(i);
        if (state.z > top.z) {
            top = state;
            identity = gLayerStatus.keyAt(i);
        }
    }

    XLOGI("[%s] LayerScreenshot top:%d (orient:%d, alpha:%d)",
        __func__, identity, top.orient, top.alpha);

    if ((top.orient & Transform::ROT_INVALID) || (0xff > top.alpha)) {
        XLOGI("    No need to freeze screen...");
        return false;
    }

    XLOGD("    Freeze screen...");
    return true;
}

void LayerScreenshot::setPerFrameData(const sp<const DisplayDevice>& hw,
        HWComposer::HWCLayerInterface& layer) {
    LayerBaseClient::setPerFrameData(hw, layer);
    layer.setBuffer(NULL);
}

void LayerScreenshot::computeGeometryOrient(
    const sp<const DisplayDevice>& hw, LayerMesh* mesh, int orient) const
{
    const Layer::State& s(drawingState());

    int hw_w = hw->getWidth();
    int hw_h = hw->getHeight();

    uint32_t flags = Transform::ROT_0;
    switch ((4 - orient) % 4) {
        case DisplayState::eOrientation90:
            flags = Transform::ROT_90;
            break;
        case DisplayState::eOrientation180:
            flags = Transform::ROT_180;
            break;
        case DisplayState::eOrientation270:
            flags = Transform::ROT_270;
            break;
        default:
            XLOGE("[%s] invalid orientation: %d", __func__, orient);
            break;
    }

    Transform orientTransform;
    if (orient & DisplayState::eOrientationSwapMask) {
        orientTransform.set(flags, hw_h, hw_w);
    } else {
        orientTransform.set(flags, hw_w, hw_h);
    }

    const Transform tr(hw->getTransform() * s.transform * orientTransform);

    if (mesh) {
        tr.transform(mesh->mVertices[0], 0, 0);
        tr.transform(mesh->mVertices[1], 0, hw_h);
        tr.transform(mesh->mVertices[2], hw_w, hw_h);
        tr.transform(mesh->mVertices[3], hw_w, 0);
        for (size_t i=0 ; i<4 ; i++) {
            mesh->mVertices[i][1] = hw_h - mesh->mVertices[i][1];
        }
    }
}

// ---------------------------------------------------------------------------

}; // namespace android