CM7手机的CRT关屏效果非常赞,在网上搜了半天,发现原来这是Android系统自带的功能,只是没有使能而已。
Android系统默认使用的关屏效果是fade,要激活旧CRT效果,需要修改以下文件,关闭fade效果。
frameworks/base/core/res/res/values/config.xml
<!-- If this is true, the screen will fade off. -->
- <bool>true</bool>
+ <bool>false</bool>
为啥如此修改就可以激活旧CRT效果,让我们跟踪下代码,先贴上相关代码:
frameworks\base\services\java\com\android\server\PowerManagerService.java
475 mAnimationSetting = 0;
476 if (windowScale > 0.5f) {
477 mAnimationSetting |= ANIM_SETTING_OFF;
478 }
2284 public void run() {
2285 if (mAnimateScreenLights) {
2286 synchronized (mLocks) {
2287 long now = SystemClock.uptimeMillis();
2288 boolean more = mScreenBrightness.stepLocked();
2289 if (more) {
2290 mScreenOffHandler.postAtTime(this, now+(1000/60));
2291 }
2292 }
2293 } else {
2294 synchronized (mLocks) {
2295 // we're turning off
2296 final boolean animate = animating && targetValue == Power.BRIGHTNESS_OFF;
2297 if (animate) {
2298 // It's pretty scary to hold mLocks for this long, and we should
2299 // redesign this, but it works for now.
2300 nativeStartSurfaceFlingerAnimation(
2301 mScreenOffReason == WindowManagerPolicy.OFF_BECAUSE_OF_PROX_SENSOR
2302 ? 0 : mAnimationSetting);
2303 }
2304 mScreenBrightness.jumpToTargetLocked();
2305 }
2306 }
2307 }
2308 }
frameworks/base/services/jni/com_android_server_PowerManagerService.cpp
131 static void android_server_PowerManagerService_nativeStartSurfaceFlingerAnimation(JNIEnv* env,
132 jobject obj, jint mode) {
133 sp<ISurfaceComposer> s(ComposerService::getComposerService());
134 s->turnElectronBeamOff(mode);
135 }
frameworks/base/services/surfaceflinger/SurfaceFlinger.cpp
2385 status_t SurfaceFlinger::turnElectronBeamOff(int32_t mode)
2386 {
2387 class MessageTurnElectronBeamOff : public MessageBase {
2388 SurfaceFlinger* flinger;
2389 int32_t mode;
2390 status_t result;
2391 public:
2392 MessageTurnElectronBeamOff(SurfaceFlinger* flinger, int32_t mode)
2393 : flinger(flinger), mode(mode), result(PERMISSION_DENIED) {
2394 }
2395 status_t getResult() const {
2396 return result;
2397 }
2398 virtual bool handler() {
2399 Mutex::Autolock _l(flinger->mStateLock);
2400 result = flinger->turnElectronBeamOffImplLocked(mode);
2401 return true;
2402 }
2403 };
2404
2405 sp<MessageBase> msg = new MessageTurnElectronBeamOff(this, mode);
2406 status_t res = postMessageSync(msg);
2407 if (res == NO_ERROR) {
2408 res = static_cast<MessageTurnElectronBeamOff*>( msg.get() )->getResult();
2409
2410 // work-around: when the power-manager calls us we activate the
2411 // animation. eventually, the "on" animation will be called
2412 // by the power-manager itself
2413 mElectronBeamAnimationMode = mode;
2414 }
2415 return res;
2416 }
2363 status_t SurfaceFlinger::turnElectronBeamOffImplLocked(int32_t mode)
2364 {
2365 DisplayHardware& hw(graphicPlane(0).editDisplayHardware());
2366 if (!hw.canDraw()) {
2367 // we're already off
2368 return NO_ERROR;
2369 }
2370 if (mode & ISurfaceComposer::eElectronBeamAnimationOff) {
2371 electronBeamOffAnimationImplLocked();
2372 }
2373
2374 // always clear the whole screen at the end of the animation
2375 glClearColor(0,0,0,1);
2376 glDisable(GL_SCISSOR_TEST);
2377 glClear(GL_COLOR_BUFFER_BIT);
2378 glEnable(GL_SCISSOR_TEST);
2379 hw.flip( Region(hw.bounds()) );
2380
2381 hw.setCanDraw(false);
2382 return NO_ERROR;
2383 }
2073 status_t SurfaceFlinger::electronBeamOffAnimationImplLocked()
2074 {
2075 status_t result = PERMISSION_DENIED;
2076
2077 if (!GLExtensions::getInstance().haveFramebufferObject())
2078 return INVALID_OPERATION;
2079
2080 // get screen geometry
2081 const DisplayHardware& hw(graphicPlane(0).displayHardware());
2082 const uint32_t hw_w = hw.getWidth();
2083 const uint32_t hw_h = hw.getHeight();
2084 const Region screenBounds(hw.bounds());
2085
2086 GLfloat u, v;
2087 GLuint tname;
2088 result = renderScreenToTextureLocked(0, &tname, &u, &v);
2089 if (result != NO_ERROR) {
2090 return result;
2091 }
2092
2093 GLfloat vtx[8];
2094 const GLfloat texCoords[4][2] = { {0,v}, {0,0}, {u,0}, {u,v} };
2095 glEnable(GL_TEXTURE_2D);
2096 glBindTexture(GL_TEXTURE_2D, tname);
2097 glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
2098 glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
2099 glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
2100 glTexCoordPointer(2, GL_FLOAT, 0, texCoords);
2101 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
2102 glVertexPointer(2, GL_FLOAT, 0, vtx);
2103
2104 class s_curve_interpolator {
2105 const float nbFrames, s, v;
2106 public:
2107 s_curve_interpolator(int nbFrames, float s)
2108 : nbFrames(1.0f / (nbFrames-1)), s(s),
2109 v(1.0f + expf(-s + 0.5f*s)) {
2110 }
2111 float operator()(int f) {
2112 const float x = f * nbFrames;
2113 return ((1.0f/(1.0f + expf(-x*s + 0.5f*s))) - 0.5f) * v + 0.5f;
2114 }
2115 };
2116
2117 class v_stretch {
2118 const GLfloat hw_w, hw_h;
2119 public:
2120 v_stretch(uint32_t hw_w, uint32_t hw_h)
2121 : hw_w(hw_w), hw_h(hw_h) {
2122 }
2123 void operator()(GLfloat* vtx, float v) {
2124 const GLfloat w = hw_w + (hw_w * v);
2125 const GLfloat h = hw_h - (hw_h * v);
2126 const GLfloat x = (hw_w - w) * 0.5f;
2127 const GLfloat y = (hw_h - h) * 0.5f;
2128 vtx[0] = x; vtx[1] = y;
2129 vtx[2] = x; vtx[3] = y + h;
2130 vtx[4] = x + w; vtx[5] = y + h;
2131 vtx[6] = x + w; vtx[7] = y;
2132 }
2133 };
2134
2135 class h_stretch {
2136 const GLfloat hw_w, hw_h;
2137 public:
2138 h_stretch(uint32_t hw_w, uint32_t hw_h)
2139 : hw_w(hw_w), hw_h(hw_h) {
2140 }
2141 void operator()(GLfloat* vtx, float v) {
2142 const GLfloat w = hw_w - (hw_w * v);
2143 const GLfloat h = 1.0f;
2144 const GLfloat x = (hw_w - w) * 0.5f;
2145 const GLfloat y = (hw_h - h) * 0.5f;
2146 vtx[0] = x; vtx[1] = y;
2147 vtx[2] = x; vtx[3] = y + h;
2148 vtx[4] = x + w; vtx[5] = y + h;
2149 vtx[6] = x + w; vtx[7] = y;
2150 }
2151 };
2152
2153 // the full animation is 24 frames
2154 const int nbFrames = 12;
2155 s_curve_interpolator itr(nbFrames, 7.5f);
2156 s_curve_interpolator itg(nbFrames, 8.0f);
2157 s_curve_interpolator itb(nbFrames, 8.5f);
2158
2159 v_stretch vverts(hw_w, hw_h);
2160 glEnable(GL_BLEND);
2161 glBlendFunc(GL_ONE, GL_ONE);
2162 for (int i=0 ; i<nbFrames ; i++) {
2163 float x, y, w, h;
2164 const float vr = itr(i);
2165 const float vg = itg(i);
2166 const float vb = itb(i);
2167
2168 // clear screen
2169 glColorMask(1,1,1,1);
2170 glClear(GL_COLOR_BUFFER_BIT);
2171 glEnable(GL_TEXTURE_2D);
2172
2173 // draw the red plane
2174 vverts(vtx, vr);
2175 glColorMask(1,0,0,1);
2176 glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
2177
2178 // draw the green plane
2179 vverts(vtx, vg);
2180 glColorMask(0,1,0,1);
2181 glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
2182
2183 // draw the blue plane
2184 vverts(vtx, vb);
2185 glColorMask(0,0,1,1);
2186 glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
2187
2188 // draw the white highlight (we use the last vertices)
2189 glDisable(GL_TEXTURE_2D);
2190 glColorMask(1,1,1,1);
2191 glColor4f(vg, vg, vg, 1);
2192 glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
2193 hw.flip(screenBounds);
2194 }
2195
2196 h_stretch hverts(hw_w, hw_h);
2197 glDisable(GL_BLEND);
2198 glDisable(GL_TEXTURE_2D);
2199 glColorMask(1,1,1,1);
2200 for (int i=0 ; i<nbFrames ; i++) {
2201 const float v = itg(i);
2202 hverts(vtx, v);
2203 glClear(GL_COLOR_BUFFER_BIT);
2204 glColor4f(1-v, 1-v, 1-v, 1);
2205 glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
2206 hw.flip(screenBounds);
2207 }
2208
2209 glColorMask(1,1,1,1);
2210 glEnable(GL_SCISSOR_TEST);
2211 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
2212 glDeleteTextures(1, &tname);
2213 return NO_ERROR;
2214 }
2215
OK,看完代码回来,首先是PowerManagerService.java中
mAnimationSetting如果标记为ANIM_SETTING_OFF,则打开旧CRT动画。
下面关屏动作run()中,因为我们将config_animateScreenLights置为false,因此mAnimateScreenLights为fasle
分支进入else,执行nativeStartSurfaceFlingerAnimation()函数。
nativeStartSurfaceFlingerAnimation()函数是一个JNI调用,在com_android_server_PowerManagerService.cpp文件中,
对应surfaceflinger的s->turnElectronBeamOff(mode)函数。
好的,现在跳入SurfaceFlinger.cpp函数,具体调用顺序是:
turnElectronBeamOff()
|
turnElectronBeamOffImplLocked()
|
electronBeamOffAnimationImplLocked()
electronBeamOffAnimationImplLocked()函数将调用openGL绘值旧CRT关屏效果,大概有24帧。