1/*
2 *  Copyright (c) 2013-14, The Linux Foundation. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
6 * met:
7 *     * Redistributions of source code must retain the above copyright
8 *       notice, this list of conditions and the following disclaimer.
9 *     * Redistributions in binary form must reproduce the above
10 *       copyright notice, this list of conditions and the following
11 *       disclaimer in the documentation and/or other materials provided
12 *       with the distribution.
13 *     * Neither the name of The Linux Foundation nor the names of its
14 *       contributors may be used to endorse or promote products derived
15 *       from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
18 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
20 * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
21 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR CLIENTS; LOSS OF USE, DATA, OR PROFITS; OR
24 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
25 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
26 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
27 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30#include <hwc_qclient.h>
31#include <IQService.h>
32#include <hwc_utils.h>
33#include <mdp_version.h>
34
35#define QCLIENT_DEBUG 0
36
37using namespace android;
38using namespace qService;
39using namespace qhwc;
40
41namespace qClient {
42
43// ----------------------------------------------------------------------------
44QClient::QClient(hwc_context_t *ctx) : mHwcContext(ctx),
45        mMPDeathNotifier(new MPDeathNotifier(ctx))
46{
47    ALOGD_IF(QCLIENT_DEBUG, "QClient Constructor invoked");
48}
49
50QClient::~QClient()
51{
52    ALOGD_IF(QCLIENT_DEBUG,"QClient Destructor invoked");
53}
54
55static void securing(hwc_context_t *ctx, uint32_t startEnd) {
56    Locker::Autolock _sl(ctx->mDrawLock);
57    //The only way to make this class in this process subscribe to media
58    //player's death.
59    IMediaDeathNotifier::getMediaPlayerService();
60
61    ctx->mSecuring = startEnd;
62    //We're done securing
63    if(startEnd == IQService::END)
64        ctx->mSecureMode = true;
65    if(ctx->proc)
66        ctx->proc->invalidate(ctx->proc);
67}
68
69static void unsecuring(hwc_context_t *ctx, uint32_t startEnd) {
70    Locker::Autolock _sl(ctx->mDrawLock);
71    ctx->mSecuring = startEnd;
72    //We're done unsecuring
73    if(startEnd == IQService::END)
74        ctx->mSecureMode = false;
75    if(ctx->proc)
76        ctx->proc->invalidate(ctx->proc);
77}
78
79void QClient::MPDeathNotifier::died() {
80    Locker::Autolock _sl(mHwcContext->mDrawLock);
81    ALOGD_IF(QCLIENT_DEBUG, "Media Player died");
82    mHwcContext->mSecuring = false;
83    mHwcContext->mSecureMode = false;
84    if(mHwcContext->proc)
85        mHwcContext->proc->invalidate(mHwcContext->proc);
86}
87
88static android::status_t screenRefresh(hwc_context_t *ctx) {
89    status_t result = NO_INIT;
90    if(ctx->proc) {
91        ctx->proc->invalidate(ctx->proc);
92        result = NO_ERROR;
93    }
94    return result;
95}
96
97static void setExtOrientation(hwc_context_t *ctx, uint32_t orientation) {
98    ctx->mExtOrientation = orientation;
99}
100
101static void isExternalConnected(hwc_context_t* ctx, Parcel* outParcel) {
102    int connected;
103    connected = ctx->dpyAttr[HWC_DISPLAY_EXTERNAL].connected ? 1 : 0;
104    outParcel->writeInt32(connected);
105}
106
107static void getDisplayAttributes(hwc_context_t* ctx, const Parcel* inParcel,
108        Parcel* outParcel) {
109    int dpy = inParcel->readInt32();
110    outParcel->writeInt32(ctx->dpyAttr[dpy].vsync_period);
111    outParcel->writeInt32(ctx->dpyAttr[dpy].xres);
112    outParcel->writeInt32(ctx->dpyAttr[dpy].yres);
113    outParcel->writeFloat(ctx->dpyAttr[dpy].xdpi);
114    outParcel->writeFloat(ctx->dpyAttr[dpy].ydpi);
115    //XXX: Need to check what to return for HDMI
116    outParcel->writeInt32(ctx->mMDP.panel);
117}
118static void setHSIC(const Parcel* inParcel) {
119    int dpy = inParcel->readInt32();
120    ALOGD_IF(0, "In %s: dpy = %d", __FUNCTION__, dpy);
121    HSICData_t hsic_data;
122    hsic_data.hue = inParcel->readInt32();
123    hsic_data.saturation = inParcel->readFloat();
124    hsic_data.intensity = inParcel->readInt32();
125    hsic_data.contrast = inParcel->readFloat();
126    //XXX: Actually set the HSIC data through ABL lib
127}
128
129
130static void setBufferMirrorMode(hwc_context_t *ctx, uint32_t enable) {
131    ctx->mBufferMirrorMode = enable;
132}
133
134static status_t getDisplayVisibleRegion(hwc_context_t* ctx, int dpy,
135                                Parcel* outParcel) {
136    // Get the info only if the dpy is valid
137    if(dpy >= HWC_DISPLAY_PRIMARY && dpy <= HWC_DISPLAY_VIRTUAL) {
138        Locker::Autolock _sl(ctx->mDrawLock);
139        if(dpy && (ctx->mExtOrientation || ctx->mBufferMirrorMode)) {
140            // Return the destRect on external, if external orienation
141            // is enabled
142            outParcel->writeInt32(ctx->dpyAttr[dpy].mDstRect.left);
143            outParcel->writeInt32(ctx->dpyAttr[dpy].mDstRect.top);
144            outParcel->writeInt32(ctx->dpyAttr[dpy].mDstRect.right);
145            outParcel->writeInt32(ctx->dpyAttr[dpy].mDstRect.bottom);
146        } else {
147            outParcel->writeInt32(ctx->mViewFrame[dpy].left);
148            outParcel->writeInt32(ctx->mViewFrame[dpy].top);
149            outParcel->writeInt32(ctx->mViewFrame[dpy].right);
150            outParcel->writeInt32(ctx->mViewFrame[dpy].bottom);
151        }
152        return NO_ERROR;
153    } else {
154        ALOGE("In %s: invalid dpy index %d", __FUNCTION__, dpy);
155        return BAD_VALUE;
156    }
157}
158
159static void pauseWFD(hwc_context_t *ctx, uint32_t pause) {
160    /* TODO: Will remove pauseWFD once all the clients start using
161     * setWfdStatus to indicate the status of WFD display
162     */
163    int dpy = HWC_DISPLAY_VIRTUAL;
164    if(pause) {
165        //WFD Pause
166        handle_pause(ctx, dpy);
167    } else {
168        //WFD Resume
169        handle_resume(ctx, dpy);
170    }
171}
172
173static void setWfdStatus(hwc_context_t *ctx, uint32_t wfdStatus) {
174
175    ALOGD_IF(HWC_WFDDISPSYNC_LOG,
176             "%s: Received a binder call that WFD state is %s",
177             __FUNCTION__,getExternalDisplayState(wfdStatus));
178    int dpy = HWC_DISPLAY_VIRTUAL;
179
180    if(wfdStatus == EXTERNAL_OFFLINE) {
181        ctx->mWfdSyncLock.lock();
182        ctx->mWfdSyncLock.signal();
183        ctx->mWfdSyncLock.unlock();
184    } else if(wfdStatus == EXTERNAL_PAUSE) {
185        handle_pause(ctx, dpy);
186    } else if(wfdStatus == EXTERNAL_RESUME) {
187        handle_resume(ctx, dpy);
188    }
189}
190
191status_t QClient::notifyCallback(uint32_t command, const Parcel* inParcel,
192        Parcel* outParcel) {
193    status_t ret = NO_ERROR;
194
195    switch(command) {
196        case IQService::SECURING:
197            securing(mHwcContext, inParcel->readInt32());
198            break;
199        case IQService::UNSECURING:
200            unsecuring(mHwcContext, inParcel->readInt32());
201            break;
202        case IQService::SCREEN_REFRESH:
203            return screenRefresh(mHwcContext);
204            break;
205        case IQService::EXTERNAL_ORIENTATION:
206            setExtOrientation(mHwcContext, inParcel->readInt32());
207            break;
208        case IQService::BUFFER_MIRRORMODE:
209            setBufferMirrorMode(mHwcContext, inParcel->readInt32());
210            break;
211        case IQService::GET_DISPLAY_VISIBLE_REGION:
212            ret = getDisplayVisibleRegion(mHwcContext, inParcel->readInt32(),
213                                    outParcel);
214            break;
215        case IQService::CHECK_EXTERNAL_STATUS:
216            isExternalConnected(mHwcContext, outParcel);
217            break;
218        case IQService::GET_DISPLAY_ATTRIBUTES:
219            getDisplayAttributes(mHwcContext, inParcel, outParcel);
220            break;
221        case IQService::SET_HSIC_DATA:
222            setHSIC(inParcel);
223            break;
224        case IQService::PAUSE_WFD:
225            pauseWFD(mHwcContext, inParcel->readInt32());
226            break;
227        case IQService::SET_WFD_STATUS:
228            setWfdStatus(mHwcContext,inParcel->readInt32());
229            break;
230        default:
231            ret = NO_ERROR;
232    }
233    return ret;
234}
235
236}
237