`
473687880
  • 浏览: 535912 次
文章分类
社区版块
存档分类
最新评论

Android源码分析之WindowManager.LayoutParams属性更新过程

 
阅读更多

1.来源

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

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

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

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

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

Window window = null;
WindowManager.LayoutParams wl;
window = getWindow();
wl = window.getAttributes();
wl.alpha = 0.5f;
window.setAttributes(wl);

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

2.过程分析

1.从Activity类开始

既然在程序中首先是在Activity类中通过getWindow()方法取得Window,那么我们就从Activity类开始。
public Window getWindow() {
    return mWindow;
}
它的实现也很简单,就是返回了一个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) ,这个函数的功能是详细的定制窗口的属性:
public void setAttributes(WindowManager.LayoutParams a) {
    mWindowAttributes.copyFrom(a);
    if (mCallback != null) {
        mCallback.onWindowAttributesChanged(mWindowAttributes);
    }
}
可见这个函数的功能就是将传进来的属性拷贝到它的成员变量里面,然后调用回调变量的方法。
在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()方法:

public void onWindowAttributesChanged(WindowManager.LayoutParams params) {
	if (mParent == null) {
		View decor = mDecor;
		if (decor != null && decor.getParent() != null) {
			getWindowManager().updateViewLayout(decor, params);
		}
	}
}

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

4.WindowManager

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

public void updateViewLayout(View view, ViewGroup.LayoutParams params) {
	if (!(params instanceof WindowManager.LayoutParams)) {
		throw new IllegalArgumentException("Params must be WindowManager.LayoutParams");
	}

	final WindowManager.LayoutParams wparams
		= (WindowManager.LayoutParams)params;

	view.setLayoutParams(wparams);

	synchronized (this) {
		int index = findViewLocked(view, true);
		ViewRootImpl root = mRoots[index];
		mParams[index] = wparams;
		root.setLayoutParams(wparams, false);
	}
}

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

5.ViewRootImpl

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

6.relayoutWindow()

在这个方法里,最重要的一句就是这一句:
int relayoutResult = sWindowSession.relayout(
		mWindow, mSeq, params,
		(int) (mView.getMeasuredWidth() * appScale + 0.5f),
		(int) (mView.getMeasuredHeight() * appScale + 0.5f),
		viewVisibility, insetsPending ? WindowManagerImpl.RELAYOUT_INSETS_PENDING : 0,
		mWinFrame, mPendingContentInsets, mPendingVisibleInsets,
		mPendingConfiguration, mSurface);

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

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

7.WindowManagerService

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

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

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

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

9.关注WindowManagerService类

WMS中有一个内部类AnimationRunnable,它实现了runnable接口,WMS服务一直运行,那么我们看一看它到底运行了什么东西:
public void run() {
	synchronized(mWindowMap) {
		mAnimationScheduled = false;
		// Update animations of all applications, including those
		// associated with exiting/removed apps
		synchronized (mAnimator) {
			Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "wmAnimate");
			final ArrayList<WindowStateAnimator> winAnimators = mAnimator.mWinAnimators;
			//mAnimator 是一个WindowAnimator的实例
			//mAnimator.mWinAnimators 实际上是一个WindowState数组 by amw
			winAnimators.clear();
			final int N = mWindows.size();//mWindows:Z有序的WindowState数组
			for (int i = 0; i < N; i++) {
				final WindowStateAnimator winAnimator = mWindows.get(i).mWinAnimator;
				if (winAnimator.mSurface != null) {
					winAnimators.add(winAnimator);
				}
			}
			mAnimator.animate();
			//上面的大概过程就是将WMS管理的WindowState放到的WindowAnimator中,
			//然后将WindowAnimator放到可系统更新过程中直到被调度
			//由类名可以推测Window的动画也是这样产生的。
			Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
		}
	}
}
可以看到,它实现上运行的东西非常简单,就是把与每个Window对应的WindowState放到到WMS的一个成员变量mAnimator的mWinAnimators数组中,然后调用mAnimator的animate()方法。
mAnimator是WindowAniamtor类的实例,它用来保存每个WindowState动画的轨迹和Surface操作。mAnimator.mWinAnimators是一个WindowStateAnimator类型的数组。

10.WindowAnimator

在WindowAnimator::animate()方法中,最关键的:
final int N = mWinAnimators.size();
for (int i = 0; i < N; i++) {
	mWinAnimators.get(i).prepareSurfaceLocked(true);//by amw
}
它针对每个WindowStateAnimator调用它的prepareSurfaceLocked()方法

11.prepareSurfaceLocked()

在这个方法里,通过
mSurface.setAlpha(mShownAlpha); 
设置Surface的属性,那么我们查看Surface.java可以知道,setAlpha()方法是一个native方法,所以它实际上调用的是android_view_surface.cpp中的Surface_setAlpha方法。这个方法又调用SurfaceControl::setAlpha()方法。它又调用SurfaceComposerClient::setAlpha方法。在这个方法里:
status_t Composer::setAlpha(const sp<SurfaceComposerClient>& client,
        SurfaceID id, float alpha) {
        LOGD("Composer::setAlpha...SurfaceID: %");//by amw
    Mutex::Autolock _l(mLock);
    layer_state_t* s = getLayerStateLocked(client, id);
    if (!s)
        return BAD_INDEX;
    s->what |= ISurfaceComposer::eAlphaChanged;
    s->alpha = alpha;
    return NO_ERROR;
}

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

12.SurfaceFlinger

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

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

        case SET_TRANSACTION_STATE: {
            LOGD("SET_TRANSACTION_STATE");
            CHECK_INTERFACE(ISurfaceComposer, data, reply);
            size_t count = data.readInt32();
            ComposerState s;
            Vector<ComposerState> state;
            state.setCapacity(count);
            for (size_t i=0 ; i<count ; i++) {
                s.read(data);
                state.add(s);
            }
            int orientation = data.readInt32();
            uint32_t flags = data.readInt32();
            setTransactionState(state, orientation, flags);       
        } break;
读取相应的值,然后调用setTransactionState()方法:
    const size_t count = state.size();
    for (size_t i=0 ; i<count ; i++) {
        const ComposerState& s(state[i]);
        sp<Client> client( static_cast<Client *>(s.client.get()) );
        transactionFlags |= setClientStateLocked(client, s.state);//set a state to the relative layer.  --by amw
    }
对每个相关联的Layer,设置它的state:

uint32_t SurfaceFlinger::setClientStateLocked(
        const sp<Client>& client,
        const layer_state_t& s)
{
        if (what & eAlphaChanged) {//................in SurfaceComposerClient.cpp, Composer::setAlpha(),  s->what |= ISurfaceComposer::eAlphaChanged;
        if (layer->setAlpha(uint8_t(255.0f*s.alpha+0.5f)))// LayerBase::setAlpha is called at there. --by amw
            flags |= eTraversalNeeded;
        }
       ...
}

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

三、参考

http://blog.csdn.net/Innost?viewmode=contents



分享到:
评论

相关推荐

    安卓Android源码——android 悬浮窗.zip

    WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL, PixelFormat.TRANSLUCENT); layoutParams.gravity = Gravity.TOP | Gravity.LEFT; // 初始位置 ``` 4. 添加视图到WindowManager:将悬浮窗的布局文件转换为...

    Android应用源码之悬浮窗 监视内容.zip

    WindowManager.LayoutParams.WRAP_CONTENT, WindowManager.LayoutParams.WRAP_CONTENT, Build.VERSION.SDK_INT &gt;= Build.VERSION_CODES.O ? WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY : ...

    安卓Android源码——android 悬浮窗.rar

    【标题】"安卓Android源码——android 悬浮窗.rar" 涉及到的是Android系统中的悬浮窗功能实现,这是Android应用开发中一个相对高级且实用的技术。悬浮窗通常被用于实现类似通知、快捷操作或者辅助工具的功能,可以在...

    安卓Andriod源码——悬浮窗.zip

    WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY, WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE, PixelFormat.TRANSLUCENT); layoutParams.gravity = Gravity.TOP | Gravity.LEFT; layoutParams.x = 0...

    Android应用源码之android 悬浮窗-IT计算机-毕业设计.zip

    总的来说,这份"Android应用源码之android 悬浮窗"资源为初学者提供了实践悬浮窗功能的实例,可以帮助他们深入理解Android系统的运行机制,提升移动应用开发技能。同时,对于毕业设计,可以作为研究Android特色功能...

    android 悬浮窗.zip项目安卓应用源码下载

    WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY, WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE, PixelFormat.TRANSLUCENT); params.gravity = Gravity.TOP | Gravity.LEFT; params.x = 0; params.y = ...

    安卓Android源码——安卓Android 天天动听悬浮歌词源码.rar

    "安卓Android源码——安卓Android 天天动听悬浮歌词源码.rar" 提供的是一份实现音乐播放器应用中悬浮歌词功能的源代码。悬浮歌词是许多音乐应用中常见的一项特性,它允许用户在使用其他应用时,歌词会以一个小窗口的...

    安卓Android源码——悬浮窗监视内容.zip

    首先,创建一个`WindowManager.LayoutParams`对象,设置其类型为`LayoutParams.TYPE_SYSTEM_ALERT`以获取足够的层级显示在其他应用之上。接着,使用`WindowManager`的`addView()`方法添加视图: ```java ...

    Android应用源码之android桌面悬浮窗效果进阶 仿360手机卫士、淘宝手机助手_Android.zip

    WindowManager.LayoutParams.TYPE_SYSTEM_ALERT, WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE, PixelFormat.TRANSLUCENT); params.gravity = Gravity.TOP | Gravity.LEFT; params.x = 0; params.y = 0; ...

    移动应用Android 视频浮动窗口源码.rar

    WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE, PixelFormat.TRANSLUCENT); params.gravity = Gravity.TOP | Gravity.LEFT; // 设置初始位置 params.x = 0; params.y = 0; wm.addView(floatingVideoView, ...

    安卓悬浮窗相关-浮动窗口播放器.rar

    WindowManager.LayoutParams.WRAP_CONTENT, WindowManager.LayoutParams.WRAP_CONTENT, WindowManager.LayoutParams.TYPE_PHONE, WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE, PixelFormat.TRANSLUCENT); ...

    安卓Android源码——视频浮动窗口源码.zip

    这个压缩包“安卓Android源码——视频浮动窗口源码.zip”提供了相关的源代码,帮助开发者理解和实现这样的功能。 首先,我们需要了解的是Android系统的权限管理。在Android 4.1(API级别16)之后,系统引入了浮动...

    Android应用源码之android 悬浮窗.zip

    例如,设置类型为`LayoutParams.TYPE_SYSTEM_ALERT`使其在所有应用之上显示。 4. 处理悬浮窗的拖动和点击事件:你可以监听触摸事件,根据坐标计算新的位置,然后更新`LayoutParams`并重新调用`addView()`方法来移动...

    安卓Android源码——悬浮窗 监视内容.zip

    这个压缩包“安卓Android源码——悬浮窗 监视内容.zip”可能包含了一个实现悬浮窗功能的示例项目,以及用于监视设备屏幕内容的代码。 首先,我们要理解在Android中如何创建和管理悬浮窗。悬浮窗通常是通过实现`...

    android仿360 浮动小插件效果

    8. **源码分析** 通过分析360安全卫士等应用的开源代码,可以更深入地理解其内部实现机制,例如如何处理多任务下的窗口层级、如何优化性能以及如何避免与其他应用冲突等。 以上就是实现Android中360浮动小插件效果...

    android 顶层 可浮动 悬浮窗 源代码

    WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL, PixelFormat.TRANSLUCENT); params.x = ...; // x坐标 params.y = ...; // y坐标 ``` 最后,通过`...

    Android参考源码-悬浮Activity并可拖动(访悬浮歌词).zip

    WindowManager.LayoutParams.TYPE_SYSTEM_ALERT, WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE, PixelFormat.TRANSLUCENT); params.gravity = Gravity.TOP | Gravity.LEFT; params.x = 0; params.y = 100; //...

    activity不全屏

    getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN); // 全屏 ``` 这段代码应在Activity的`onCreate()`方法中调用,`requestWindowFeature()`需要...

    android桌面悬浮窗效果进阶 仿360手机卫士、淘宝手机助手-IT计算机-毕业设计.zip

    layoutParams.type = WindowManager.LayoutParams.TYPE_SYSTEM_ALERT; layoutParams.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE; // ... WindowManager windowManager = (WindowManager) ...

    android桌面悬浮窗效果 仿360手机卫士、淘宝手机助手

    "android桌面悬浮窗效果 仿360手机卫士、淘宝手机助手"这个项目旨在模仿360手机卫士和淘宝手机助手中的悬浮窗功能,通过源码分析来学习如何创建类似的功能。 首先,我们需要理解Android系统对悬浮窗的管理机制。在...

Global site tag (gtag.js) - Google Analytics