1.来源

问题的来源是因为现在的公司准备转向Android,但是又不想放弃原来的系统,所以想把原来在linux上直接跑的系统移植到Android上来,当然一大重头任务就是对原有界面库的移植和Android图形系统的修改。

我们需要对Android的图形系统加以修改,以实现原有系统的图形效果。原来的系统中有一种页面切换效果,需要将它在Android上实现出来。一开始我是在应用程序层面上,重载装载页面的viewgroup的绘制函数实现的。但是,由于view的内容太过复杂以及在页面切换时系统需要做很多事情,所以切换的动画过程很卡,出现跳帧的现象。

所以我们想到在Android的底层,也就在SurfaceFlinger这个层面上做这种效果。

要想在SurfaceFlinger上面做出这种页面切换效果,而且能根据程序设置决定效果的样式,那么我们需要从应用程序层传递标志到SurfaceFlinger。

我们在SurfaceFlinger里的drawWithOpenGl里,可以得到一个Layer的alpha值,而在应用程序里,我们可以通过来改变此activity对应的surface的alpha值。

[cpp] view plain copy
  1. Windowwindow=null;
  2. WindowManager.LayoutParamswl;
  3. window=getWindow();
  4. wl=window.getAttributes();
  5. wl.alpha=0.5f;
  6. window.setAttributes(wl);

所以需要以Window的LayoutParams.alpha为例,研究Android的图形系统是怎样将WindowManager.LayoutParams里的alpha属性传递到SurfaceFlinger中的drawWithOpenGL中去的。

2.过程分析

1.从Activity类开始

既然在程序中首先是在Activity类中通过getWindow()方法取得Window,那么我们就从Activity类开始。 [java] view plain copy
  1. publicWindowgetWindow(){
  2. returnmWindow;
  3. }
它的实现也很简单,就是返回了一个Window的实例mWindow.
那么我们转到Window类中去看看。

2.Window类

找到它的位置:./frameworks/base/core/java/android/view/Window.java,按它的类的说明:它是一个顶层的窗口外观和行为策略的抽象类。它的实例应该被用作顶层窗口而添加到Window Manager中去。它提供标准的UI策略,例如背景,标题区域以及默认键处理等。 它有一个惟一的实现类:android.policy.PhoneWindow. 我们先看public void setAttributes(WindowManager.LayoutParams a) ,这个函数的功能是详细的定制窗口的属性: [cpp] view plain copy
  1. publicvoidsetAttributes(WindowManager.LayoutParamsa){
  2. mWindowAttributes.copyFrom(a);
  3. if(mCallback!=null){
  4. mCallback.onWindowAttributesChanged(mWindowAttributes);
  5. }
  6. }
可见这个函数的功能就是将传进来的属性拷贝到它的成员变量里面,然后调用回调变量的方法。 在Window类里面找到mCallback的赋值,发现它是通过Window::setCallback()方法对这个变量赋值的。接下来就要找Window::setCallback()方法的调用。由于我们的Activity类中有mWindow变量,所以它应该调用了setCallback().我们回到Activity.java中,看getWindow()方

3.再回到Activity

在Activity::attch()方法里,果然有mWindow成员的赋值以及设置回调对象:mWindow.setCallback(this);从这一句发现,山Window类设置的回调对象就是Activity类,所以在第2小节里,回调对象调用onWindowAttributesChanged()方法也是就调用Activity::onWindowAttributesChanged()方法:

[java] view plain copy
  1. publicvoidonWindowAttributesChanged(WindowManager.LayoutParamsparams){
  2. if(mParent==null){
  3. Viewdecor=mDecor;
  4. if(decor!=null&&decor.getParent()!=null){
  5. getWindowManager().updateViewLayout(decor,params);
  6. }
  7. }
  8. }

这里面的getWindowManager()方法返回Activity类的WindowManager成员变量。经过层层追踪,这个mWindowManager成员变量其实就是一个WindowManagerImpl对象经过包装后的LocalWindowManager对象的实例。

4.WindowManager

它的updateViewLayout()方法的实现在WindowManagerImpl.java中:

[java] view plain copy
  1. publicvoidupdateViewLayout(Viewview,ViewGroup.LayoutParamsparams){
  2. if(!(paramsinstanceofWindowManager.LayoutParams)){
  3. thrownewIllegalArgumentException("ParamsmustbeWindowManager.LayoutParams");
  4. }
  5. finalWindowManager.LayoutParamswparams
  6. =(WindowManager.LayoutParams)params;
  7. view.setLayoutParams(wparams);
  8. synchronized(this){
  9. intindex=findViewLocked(view,true);
  10. ViewRootImplroot=mRoots[index];
  11. mParams[index]=wparams;
  12. root.setLayoutParams(wparams,false);
  13. }
  14. }

这段代码的大概过程是:先取得先将传入的参数转换成WindowManager.LayoutParams, 然后根据第一个参数 view(其实它是一个decoview)找到此Activity对象的mRoot,然后调用它的setLayoutParams()方法。

5.ViewRootImpl

在ViewRootImpl.java中,我们查看ViewRootImpl::setLayoutParams()方法,它只是将传入的窗口属性参数保存起来,然后设置属性变化标志符,然后就调用了scheduleTraversals()方法。那么经过调度,最终会运行performTraversals()这个方法。在这个方法里,由会调用relayoutWindow()方法

6.relayoutWindow()

在这个方法里,最重要的一句就是这一句: [java] view plain copy
  1. intrelayoutResult=sWindowSession.relayout(
  2. mWindow,mSeq,params,
  3. (int)(mView.getMeasuredWidth()*appScale+0.5f),
  4. (int)(mView.getMeasuredHeight()*appScale+0.5f),
  5. viewVisibility,insetsPending?WindowManagerImpl.RELAYOUT_INSETS_PENDING:0,
  6. mWinFrame,mPendingContentInsets,mPendingVisibleInsets,
  7. mPendingConfiguration,mSurface);

由ViewRootImpl的成员变量mWindowSession调用它的方法relayout对窗口重新布局。

sWindowSession其实是与WindowManagerService类进行通信的一个会话,它最终调用的是WindowManagerService::relayoutWindow()方法

7.WindowManagerService

WindowManagerService::relayoutWindow()的主要作用是将传入的窗口属性保存到与每个Window相关联的WindowState上去: [cpp] view plain copy
  1. //通过session和client,在HashMap<IBinder,WindowState>找到WindowState变量
  2. WindowStatewin=windowForClientLocked(session,client,false);
  3. 。。。//将属性进行相应的转换后保存到WindowState
  4. if((attrChanges&WindowManager.LayoutParams.ALPHA_CHANGED)!=0){//这二个条件来自WindowManager.java,先不管
  5. winAnimator.mAlpha=attrs.alpha;
  6. }

winAnimator是WindowState实例的一个成员,它用来实现状态变化时的动画效果。

8.在java层面上属性设置完毕

到一步,我们的属性设置从Activity类一直传递到WindowManager中的WindowState中的WindowStateAnimator实例中保存起来,那么它什么时候传递到native的SurfaceFlinger中呢。

9.关注WindowManagerService类

WMS中有一个内部类AnimationRunnable,它实现了runnable接口,WMS服务一直运行,那么我们看一看它到底运行了什么东西: [java] view plain copy
  1. publicvoidrun(){
  2. synchronized(mWindowMap){
  3. mAnimationScheduled=false;
  4. //Updateanimationsofallapplications,includingthose
  5. //associatedwithexiting/removedapps
  6. synchronized(mAnimator){
  7. Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER,"wmAnimate");
  8. finalArrayList<WindowStateAnimator>winAnimators=mAnimator.mWinAnimators;
  9. //mAnimator是一个WindowAnimator的实例
  10. //mAnimator.mWinAnimators实际上是一个WindowState数组byamw
  11. winAnimators.clear();
  12. finalintN=mWindows.size();//mWindows:Z有序的WindowState数组
  13. for(inti=0;i<N;i++){
  14. finalWindowStateAnimatorwinAnimator=mWindows.get(i).mWinAnimator;
  15. if(winAnimator.mSurface!=null){
  16. winAnimators.add(winAnimator);
  17. }
  18. }
  19. mAnimator.animate();
  20. //上面的大概过程就是将WMS管理的WindowState放到的WindowAnimator中,
  21. //然后将WindowAnimator放到可系统更新过程中直到被调度
  22. //由类名可以推测Window的动画也是这样产生的。
  23. Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
  24. }
  25. }
  26. }
可以看到,它实现上运行的东西非常简单,就是把与每个Window对应的WindowState放到到WMS的一个成员变量mAnimator的mWinAnimators数组中,然后调用mAnimator的animate()方法。 mAnimator是WindowAniamtor类的实例,它用来保存每个WindowState动画的轨迹和Surface操作。mAnimator.mWinAnimators是一个WindowStateAnimator类型的数组。

10.WindowAnimator

在WindowAnimator::animate()方法中,最关键的: [cpp] view plain copy
  1. finalintN=mWinAnimators.size();
  2. for(inti=0;i<N;i++){
  3. mWinAnimators.get(i).prepareSurfaceLocked(true);//byamw
  4. }
它针对每个WindowStateAnimator调用它的prepareSurfaceLocked()方法

11.prepareSurfaceLocked()

在这个方法里,通过 [cpp] view plain copy
  1. mSurface.setAlpha(mShownAlpha);
设置Surface的属性,那么我们查看Surface.java可以知道,setAlpha()方法是一个native方法,所以它实际上调用的是android_view_surface.cpp中的Surface_setAlpha方法。这个方法又调用SurfaceControl::setAlpha()方法。它又调用SurfaceComposerClient::setAlpha方法。在这个方法里: [cpp] view plain copy
  1. status_tComposer::setAlpha(constsp<SurfaceComposerClient>&client,
  2. SurfaceIDid,floatalpha){
  3. LOGD("Composer::setAlpha...SurfaceID:%");//byamw
  4. Mutex::Autolock_l(mLock);
  5. layer_state_t*s=getLayerStateLocked(client,id);
  6. if(!s)
  7. returnBAD_INDEX;
  8. s->what|=ISurfaceComposer::eAlphaChanged;
  9. s->alpha=alpha;
  10. returnNO_ERROR;
  11. }

它得到LayerState,设置它的事件类型以及相应的值。然后返回。

12.SurfaceFlinger

由于surfaceFlinger继承自BnSurfaceComposerClient,所以它能响应来自BpSurfaceComposerClient的请求。响应函数为SurfaceFlinger::onTransact();

在这里面就是根据消息类型调用不同的方法来处理,对我们关注的alpha的值的处理:

[cpp] view plain copy
  1. caseSET_TRANSACTION_STATE:{
  2. LOGD("SET_TRANSACTION_STATE");
  3. CHECK_INTERFACE(ISurfaceComposer,data,reply);
  4. size_tcount=data.readInt32();
  5. ComposerStates;
  6. Vector<ComposerState>state;
  7. state.setCapacity(count);
  8. for(size_ti=0;i<count;i++){
  9. s.read(data);
  10. state.add(s);
  11. }
  12. intorientation=data.readInt32();
  13. uint32_tflags=data.readInt32();
  14. setTransactionState(state,orientation,flags);
  15. }break;
读取相应的值,然后调用setTransactionState()方法: [cpp] view plain copy
  1. constsize_tcount=state.size();
  2. for(size_ti=0;i<count;i++){
  3. constComposerState&s(state[i]);
  4. sp<Client>client(static_cast<Client*>(s.client.get()));
  5. transactionFlags|=setClientStateLocked(client,s.state);//setastatetotherelativelayer.--byamw
  6. }
对每个相关联的Layer,设置它的state:

[cpp] view plain copy
  1. uint32_tSurfaceFlinger::setClientStateLocked(
  2. constsp<Client>&client,
  3. constlayer_state_t&s)
  4. {
  5. if(what&eAlphaChanged){//................inSurfaceComposerClient.cpp,Composer::setAlpha(),s->what|=ISurfaceComposer::eAlphaChanged;
  6. if(layer->setAlpha(uint8_t(255.0f*s.alpha+0.5f)))//LayerBase::setAlphaiscalledatthere.--byamw
  7. flags|=eTraversalNeeded;
  8. }
  9. ...
  10. }

从上面可以看到,每个Layer 根据它的state,重新设置了它的alpha值。
更多 学习资料

更多相关文章

  1. [转]快速切换Android工程版本的方法
  2. Android_TextView属性XML详解
  3. 图解 Android 动画中 android:pivotX 和 android:pivotY 属性的
  4. Android中使用Handler机制更新UI的两种方法
  5. Android中设置关键字高亮的方法
  6. ProgressBar属性小结

随机推荐

  1. android MediaCodec ACodec OMX tips
  2. Android(安卓)aar与 jar
  3. 备忘的小知识
  4. Android中使用DownloadManager下载并安装
  5. EventThread线程对VSync的接收
  6. 在Android中借助TensorFlow使用机器学习(
  7. Tensorflow编译android平台的so库和jar包
  8. Android(安卓)studio JavaDoc的使用
  9. Android——systrace使用分析
  10. android,actionbar,menu显示,图片,菜单禁