Discuz! Board

 找回密码
 立即注册
搜索
热搜: 活动 交友 discuz
查看: 2|回复: 2
打印 上一主题 下一主题

关于android壁纸的一些文章

[复制链接]

1198

主题

2060

帖子

7058

积分

超级版主

Rank: 8Rank: 8

积分
7058
跳转到指定楼层
楼主
发表于 2016-5-2 22:07:20 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
本帖最后由 zangcf 于 2016-5-2 22:34 编辑

Android WallpaperManager解析及BUG解决:::http://blog.csdn.net/zyplus/article/details/8260478
析壁纸机制分析:::http://blog.csdn.net/guoqifa29/article/details/40105839
第8章 深入理解Android壁纸:::
http://blog.csdn.net/innost/article/details/47660645
回复

使用道具 举报

1198

主题

2060

帖子

7058

积分

超级版主

Rank: 8Rank: 8

积分
7058
沙发
 楼主| 发表于 2016-5-2 22:08:56 | 只看该作者

析壁纸机制分析

文章记录自己的学习过程,供日后参考。

第一部分:通信通道的建立

首先要知道壁纸设置的大体流程:上层应用调用wallpaperManager.setStream()或其他接口进行设置壁纸,WallpaperManagerService首先将壁纸copy到/data/system/user/0/目录下,WallpaperManagerService对该目录注册了一个WallpaperObserver,拷贝壁纸成功后会触发调用WallpaperObserver.onEvent()函数,onEvent()函数首先调用notifyCallbacksLocked()触发回调,然后再调用bindWallpaperComponentLocked()做进行进一步的壁纸更换。虽然整个壁纸机制有WallpaperManager、WallpaperService、ImageWallpaper、WallpaperManagerService、Globals、DrawableEngine、WallpaperData、WallpaperConnection等数据结构,感觉挺复杂的,我们应该剥离他的外表,看清他的本质。我们只要搞清了他们之间怎么交互的?交流些什么东西?就搞清楚了整个壁纸机制,说白了只要搞清楚IWallpaperService.aidl、IWallpaperEngine.aidl、IWallpaperConnection.aidl这三个文件就OK了,因为这三个文件是通信的关键所在。下面这张图代表了WallpaperService与WallpaperManagerService的交互关系。

1.IWallpaperService.aidl


[html] view plain copy


  • oneway interface IWallpaperService {  
  •     void attach(IWallpaperConnection connection,  
  •             IBinder windowToken, int windowType, boolean isPreview,  
  •             int reqWidth, int reqHeight);  
  • }  

aidl语言专为Binder设计,因此里面的函数可看做是通信接口。


(1).WallpaperService.IWallpaperServiceWrapper extends IWallpaperService.Stub;

(2).WallpaperService.onBind()


[html] view plain copy


  • /**  
  •   * Implement to return the implementation of the internal accessibility  
  •   * service interface.  Subclasses should not override.  
  •   */  
  • @Override  
  • public final IBinder onBind(Intent intent) {  
  •      return new IWallpaperServiceWrapper(this);  
  • }  

从上面两点可以知道:IWallpaperService的Binder本地端在WallpaperService中;WallpaperService服务将是调用mContext.bindService()启动的;IWallpaperService的代理对象将在ServiceConnection.onServiceConnected()中获取。很容易验证WallPaperManagerService中确实是这么干的。


WallPaperManagerService.bindWallpaperComponentLocked():


[html] view plain copy


  • boolean bindWallpaperComponentLocked(ComponentName componentName, boolean force,  
  •          boolean fromUser, WallpaperData wallpaper, IRemoteCallback reply) {  
  •          ........  
  •          Intent intent = new Intent(WallpaperService.SERVICE_INTERFACE);  
  •          ........  
  •          WallpaperConnection newConn = new WallpaperConnection(wi, wallpaper);  
  •          intent.setComponent(componentName);  
  •          intent.putExtra(Intent.EXTRA_CLIENT_LABEL,  
  •                  com.android.internal.R.string.wallpaper_binding_label);  
  •          intent.putExtra(Intent.EXTRA_CLIENT_INTENT, PendingIntent.getActivityAsUser(  
  •                  mContext, 0,  
  •                  Intent.createChooser(new Intent(Intent.ACTION_SET_WALLPAPER),  
  •                          mContext.getText(com.android.internal.R.string.chooser_wallpaper)),  
  •                  0, null, new UserHandle(serviceUserId)));  
  •          if (!mContext.bindServiceAsUser(intent, newConn,  
  •                  Context.BIND_AUTO_CREATE | Context.BIND_SHOWING_UI,  
  •                  new UserHandle(serviceUserId))) {  
  •         ..........  
  •          }  
  • }  

文章最开头就说了,每次设置壁纸都会调用bindWallpaperComponentLocked()函数,也就是说每次设置壁纸都会重新new WallpaperConnection,重新调用mContext.bindServiceAsUser()绑定启动WallpaperService,为啥要每次重新bind一次呢?防止systemUI挂掉,无法设置壁纸?不管了,反正记住每次设置壁纸时都会bind一次WallpaperService,并且调用WallpaperConnection.onServiceConnected()函数。onServiceConnected()函数中真的获取了IWallpaperService的Binder代理对象。



[html] view plain copy


  • public void onServiceConnected(ComponentName name, IBinder service) {  
  •        synchronized (mLock) {  
  •            if (mWallpaper.connection == this) {  
  •                mWallpaper.lastDiedTime = SystemClock.uptimeMillis();  
  •                mService = IWallpaperService.Stub.asInterface(service);  
  •                attachServiceLocked(this, mWallpaper);  
  •                // XXX should probably do saveSettingsLocked() later  
  •                // when we have an engine, but I'm not sure about  
  •                // locking there and anyway we always need to be able to  
  •                // recover if there is something wrong.  
  •                saveSettingsLocked(mWallpaper);  
  •            }  
  •        }  
  •    }  

mService = IWallpaperService.Stub.asInterface(service);语句获取了IWallpaperService的Binder代理对象。再看看WallpaperConnection.onServiceConnected()函数中调用WallPaperManagerService.attachServiceLocked()干什么?



[html] view plain copy


  • void attachServiceLocked(WallpaperConnection conn, WallpaperData wallpaper) {  
  •      try {  
  •          conn.mService.attach(conn, conn.mToken,  
  •                  WindowManager.LayoutParams.TYPE_WALLPAPER, false,  
  •                  wallpaper.width, wallpaper.height);  
  •      } catch (RemoteException e) {  
  •          Slog.w(TAG, "Failed attaching wallpaper; clearing", e);  
  •          if (!wallpaper.wallpaperUpdating) {  
  •              bindWallpaperComponentLocked(null, false, false, wallpaper, null);  
  •          }  
  •      }  
  • }  

嗯,跨Binder调用IWallpaperService本地端的attach()。看看attach()做了什么?



[html] view plain copy


  • public void attach(IWallpaperConnection conn, IBinder windowToken,  
  •          int windowType, boolean isPreview, int reqWidth, int reqHeight) {  
  •      new IWallpaperEngineWrapper(mTarget, conn, windowToken,  
  •              windowType, isPreview, reqWidth, reqHeight);  
  • }  

直接new IWallpaperEngineWrapper对象,注意传进来的参数,包含壁纸显示参数。IWallpaperEngineWrapper extends IWallpaperEngine.Stub implements HandlerCaller.Callback,所以又知道了IWallpaperEngine的Binder本地端保存在WallpaperService中,代理端返回给WallPaperManagerService.WallpaperConnection.mEngine变量的呢?这个研究到后边应该自然就知道了。IWallpaperEngineWrapper的构造函数将被调用,在构造函数中会post一个handle消息DO_ATTACH,然后消息在executeMessage()中执行:

[html] view plain copy


  • switch (message.what) {  
  •       case DO_ATTACH: {  
  •           try {  
  •               mConnection.attachEngine(this);  
  •           } catch (RemoteException e) {  
  •               Log.w(TAG, "Wallpaper host disappeared", e);  
  •               return;  
  •           }  
  •           Engine engine = onCreateEngine();  
  •           mEngine = engine;  
  •           mActiveEngines.add(engine);  
  •           engine.attach(this);  
  •           return;  
  •       }  

感觉牵涉的越来越多了,没关系,一个个来分析。mConnection的值从attach()函数的参数获取,很容易知道就是IWallpaperConnection的Binder代理对象,本地对象就是WallpaperConnection,在WallpaperManagerService中。上面代码调用mConnection.attachEngine(this), this指向IWallpaperEngineWrapper,说白了就是把IWallpaperEngine的Binder代理对象传给WallpaperManagerService,至此,WallpaperManagerService与WallpaperService的三条Binder通信通道全部建立起来了。

总结:设置壁纸时,触发调用WallpaperManagerService.bindWallpaperComponentLocked(),函数会bindService(WallpaperService),在bind过程中WallpaperService返回一个IWallpaperService的代理对象给WallpaperManagerService,WallpaperManagerService侧接着调用IWallpaperService.attach()函数将WallpaperManagerService侧的IWallpaperConnection代理对象传给WallpaperService,WallpaperService侧同时也会调用刚传过来的IWallpaperConnection.attachEngine()将IWallpaperEngine的代理对象传过去。嗯,有点乱。

从上面的图中,看出现在attach()、attachEngine()两个函数光荣地完成了使命。下面来分析engineShown()、setDesiredSize()、setVisibility()、dispatchPointer()、dispatchWallpaperCommand()五个函数。

1.engineShown()

先看下这个函数的实现:

[html] view plain copy


  • public void engineShown(IWallpaperEngine engine) {  
  •     synchronized (mLock) {  
  •         if (mReply != null) {  
  •             long ident = Binder.clearCallingIdentity();  
  •             try {  
  •                 mReply.sendResult(null);  
  •             } catch (RemoteException e) {  
  •                 Binder.restoreCallingIdentity(ident);  
  •             }  
  •             mReply = null;  
  •         }  
  •     }  
  • }  

mReply是从bindWallpaperComponentLocked()函数的参数赋值的,是个null。所以这个函数基本没干什么,但是可以通过名字知道,WallpaperService这边将壁纸显示成功后会调用这个函数。那就研究下在哪里调用engineShown(),这样可以反推显示等逻辑所在的地方。嗯,engineShown()在IWallpaperEngineWrapper.reportShown()中调用。


[html] view plain copy


  • public void reportShown() {  
  •     if (!mShownReported) {  
  •         mShownReported = true;  
  •         try {  
  •             mConnection.engineShown(this);  
  •         } catch (RemoteException e) {  
  •             Log.w(TAG, "Wallpaper host disappeared", e);  
  •             return;  
  •         }  
  •     }  
  • }  

再看看reportShown()在哪调用,发现在updateSurface()中调用,浏览下updateSurface()函数,可以肯定壁纸刷新就在updateSurface()中完成。哈哈,下面来研究这个updateSurface()函数。


这个函数在很多地方调用,可以看做是壁纸刷新函数。

[html] view plain copy


  • void updateSurface(boolean forceRelayout, boolean forceReport, boolean redrawNeeded) {  
  •     if (mDestroyed) {  
  •         Log.w(TAG, "Ignoring updateSurface: destroyed");  
  •     }  
  •       
  •     int myWidth = mSurfaceHolder.getRequestedWidth();  
  •     if (myWidth <= 0) myWidth = ViewGroup.LayoutParams.MATCH_PARENT;  
  •     int myHeight = mSurfaceHolder.getRequestedHeight();  
  •     if (myHeight <= 0) myHeight = ViewGroup.LayoutParams.MATCH_PARENT;  
  •       
  •     final boolean creating = !mCreated;  
  •     final boolean surfaceCreating = !mSurfaceCreated;  
  •     final boolean formatChanged = mFormat != mSurfaceHolder.getRequestedFormat();  
  •     boolean sizeChanged = mWidth != myWidth || mHeight != myHeight;  
  •     final boolean typeChanged = mType != mSurfaceHolder.getRequestedType();  
  •     final boolean flagsChanged = mCurWindowFlags != mWindowFlags ||  
  •             mCurWindowPrivateFlags != mWindowPrivateFlags;  
  •     if (forceRelayout || creating || surfaceCreating || formatChanged || sizeChanged  
  •             || typeChanged || flagsChanged || redrawNeeded  
  •             || !mIWallpaperEngine.mShownReported) {  
  •   
  •         if (DEBUG) Log.v(TAG, "Changes: creating=" + creating  
  •                 + " format=" + formatChanged + " size=" + sizeChanged);  
  •   
  •         try {  
  •             mWidth = myWidth;  
  •             mHeight = myHeight;  
  •             mFormat = mSurfaceHolder.getRequestedFormat();  
  •             mType = mSurfaceHolder.getRequestedType();  
  •   
  •             mLayout.x = 0;  
  •             mLayout.y = 0;  
  •             mLayout.width = myWidth;  
  •             mLayout.height = myHeight;  
  •               
  •             mLayout.format = mFormat;  
  •               
  •             mCurWindowFlags = mWindowFlags;  
  •             mLayout.flags = mWindowFlags  
  •                     | WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS  
  •                     | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN  
  •                     | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE  
  •                     ;  
  •             mCurWindowPrivateFlags = mWindowPrivateFlags;  
  •             mLayout.privateFlags = mWindowPrivateFlags;  
  •   
  •             mLayout.memoryType = mType;  
  •             mLayout.token = mWindowToken;  
  •   
  •             if (!mCreated) {              //创建输入通道、addToDisplay()、创建一个触摸事件接受者;  
  •                 mLayout.type = mIWallpaperEngine.mWindowType;  
  •                 mLayout.gravity = Gravity.START|Gravity.TOP;  
  •                 mLayout.setTitle(WallpaperService.this.getClass().getName());  
  •                 mLayout.windowAnimations =  
  •                         com.android.internal.R.style.Animation_Wallpaper;  
  •                 mInputChannel = new InputChannel();  
  •                 if (mSession.addToDisplay(mWindow, mWindow.mSeq, mLayout, View.VISIBLE,  
  •                     Display.DEFAULT_DISPLAY, mContentInsets, mInputChannel) < 0) {  
  •                     Log.w(TAG, "Failed to add window while updating wallpaper surface.");  
  •                     return;  
  •                 }  
  •                 mCreated = true;  
  •   
  •                 mInputEventReceiver = new WallpaperInputEventReceiver(  
  •                         mInputChannel, Looper.myLooper());  
  •             }  
  •               
  •             mSurfaceHolder.mSurfaceLock.lock();  
  •             mDrawingAllowed = true;  
  •   
  •             final int relayoutResult = mSession.relayout(            //relayout();  
  •                 mWindow, mWindow.mSeq, mLayout, mWidth, mHeight,  
  •                     View.VISIBLE, 0, mWinFrame, mOverscanInsets, mContentInsets,  
  •                     mVisibleInsets, mConfiguration, mSurfaceHolder.mSurface);  
  •   
  •             if (DEBUG) Log.v(TAG, "New surface: " + mSurfaceHolder.mSurface  
  •                     + ", frame=" + mWinFrame);  
  •               
  •             int w = mWinFrame.width();  
  •             if (mCurWidth != w) {  
  •                 sizeChanged = true;  
  •                 mCurWidth = w;  
  •             }  
  •             int h = mWinFrame.height();  
  •             if (mCurHeight != h) {  
  •                 sizeChanged = true;  
  •                 mCurHeight = h;  
  •             }  
  •   
  •             mSurfaceHolder.setSurfaceFrameSize(w, h);           //设置surface Frame Size;  
  •             mSurfaceHolder.mSurfaceLock.unlock();  
  •   
  •             if (!mSurfaceHolder.mSurface.isValid()) {  
  •                 reportSurfaceDestroyed();  
  •                 if (DEBUG) Log.v(TAG, "Layout: Surface destroyed");  
  •                 return;  
  •             }  
  •   
  •             boolean didSurface = false;  
  •   
  •             try {  
  •                 mSurfaceHolder.ungetCallbacks();  
  •   
  •                 if (surfaceCreating) {  
  •                     mIsCreating = true;  
  •                     didSurface = true;  
  •                     if (DEBUG) Log.v(TAG, "onSurfaceCreated("  
  •                             + mSurfaceHolder + "): " + this);  
  •                     onSurfaceCreated(mSurfaceHolder);            //创建surface;  
  •                     SurfaceHolder.Callback callbacks[] = mSurfaceHolder.getCallbacks();  
  •                     if (callbacks != null) {  
  •                         for (SurfaceHolder.Callback c : callbacks) {  
  •                             c.surfaceCreated(mSurfaceHolder);  
  •                         }  
  •                     }  
  •                 }  
  •   
  •                 redrawNeeded |= creating || (relayoutResult  
  •                         & WindowManagerGlobal.RELAYOUT_RES_FIRST_TIME) != 0;  
  •   
  •                 if (forceReport || creating || surfaceCreating  
  •                         || formatChanged || sizeChanged) {  
  •                     if (DEBUG) {  
  •                         RuntimeException e = new RuntimeException();  
  •                         e.fillInStackTrace();  
  •                         Log.w(TAG, "forceReport=" + forceReport + " creating=" + creating  
  •                                 + " formatChanged=" + formatChanged  
  •                                 + " sizeChanged=" + sizeChanged, e);  
  •                     }  
  •                     if (DEBUG) Log.v(TAG, "onSurfaceChanged("  
  •                             + mSurfaceHolder + ", " + mFormat  
  •                             + ", " + mCurWidth + ", " + mCurHeight  
  •                             + "): " + this);  
  •                     didSurface = true;  
  •                     onSurfaceChanged(mSurfaceHolder, mFormat,  
  •                             mCurWidth, mCurHeight);  
  •                     SurfaceHolder.Callback callbacks[] = mSurfaceHolder.getCallbacks();  
  •                     if (callbacks != null) {  
  •                         for (SurfaceHolder.Callback c : callbacks) {  
  •                             c.surfaceChanged(mSurfaceHolder, mFormat,  
  •                                     mCurWidth, mCurHeight);  
  •                         }  
  •                     }  
  •                 }  
  •   
  •                 if (redrawNeeded) {  
  •                     onSurfaceRedrawNeeded(mSurfaceHolder);  
  •                     SurfaceHolder.Callback callbacks[] = mSurfaceHolder.getCallbacks();  
  •                     if (callbacks != null) {  
  •                         for (SurfaceHolder.Callback c : callbacks) {  
  •                             if (c instanceof SurfaceHolder.Callback2) {  
  •                                 ((SurfaceHolder.Callback2)c).surfaceRedrawNeeded(  
  •                                         mSurfaceHolder);  
  •                             }  
  •                         }  
  •                     }  
  •                 }  
  •   
  •                 if (didSurface && !mReportedVisible) {  
  •                     // This wallpaper is currently invisible, but its  
  •                     // surface has changed.  At this point let's tell it  
  •                     // again that it is invisible in case the report about  
  •                     // the surface caused it to start running.  We really  
  •                     // don't want wallpapers running when not visible.  
  •                     if (mIsCreating) {  
  •                         // Some wallpapers will ignore this call if they  
  •                         // had previously been told they were invisble,  
  •                         // so if we are creating a new surface then toggle surface  
  •                         // the state to get them to notice.  
  •                         if (DEBUG) Log.v(TAG, "onVisibilityChanged(true) at surface: "  
  •                                 + this);  
  •                         onVisibilityChanged(true);  
  •                     }  
  •                     if (DEBUG) Log.v(TAG, "onVisibilityChanged(false) at surface: "  
  •                                 + this);  
  •                     onVisibilityChanged(false);  
  •                 }  
  •   
  •             } finally {  
  •                 mIsCreating = false;  
  •                 mSurfaceCreated = true;  
  •                 if (redrawNeeded) {  
  •                     mSession.finishDrawing(mWindow);  
  •                 }  
  •                 mIWallpaperEngine.reportShown();  
  •             }  
  •         } catch (RemoteException ex) {  
  •         }  
  •         if (DEBUG) Log.v(  
  •             TAG, "Layout: x=" + mLayout.x + " y=" + mLayout.y +  
  •             " w=" + mLayout.width + " h=" + mLayout.height);  
  •     }  
  • }  


2.setDesiredSize()

没啥用的一个函数。

3.setVisibility()

没看到有调用。

4.dispatchPointer()

接受触摸事件。动态壁纸需要接受触摸事件。

第二部分:设置一张壁纸WallpaperService中的调用逻辑

1.DO_DETACH

从WallpaperManagerService.detachWallpaperLocked()-->IWallpaperEngineWrapper.destroy()-->Engine.detach()

a.mSession.remove(mWindow);---------------------移除壁纸窗口;

b.mSurfaceHolder.mSurface.release();------------释放surface;

c.mInputChannel.dispose();--------------------------关闭输入通道;

主要做了三件事:remove窗口;释放surface;关闭输入通道;

2.DO_ATTACH

从WallpaperManagerService.attachServiceLocked()-->IWallpaperService.attach()

a.mSurfaceHolder.setSizeFromLayout();--------------------------------重置surface的尺寸为(-1,-1);

b.mSession = WindowManagerGlobal.getWindowSession();-------获取WindowSession;

c.registerReceiver(mReceiver, filter);--------------------------------------注册ACTION_SCREEN_ON和ACTION_SCREEN_OFF广播接收器;

d.Engine.onCreate(mSurfaceHolder);-->updateSurfaceSize():

    1).mWallpaperManager.forgetLoadedWallpaper();------------------清除mWallpaper和mDefaultWallpaper值;

    2).updateWallpaperLocked();-->mBackground = mWallpaperManager.getBitmap();-----------获取壁纸赋给mBackground;

    3).surfaceHolder.setFixedSize(surfaceWidth, surfaceHeight);----从mBackground中取值来修正surface的大小;

e.updateSurface(false, false, false);----------------------------------------因为前面清除了surface,所以这个函数肯定会重新new Surface;

    1). mInputChannel = new InputChannel();

    2).mSession.addToDisplay(mWindow, mWindow.mSeq, mLayout, View.VISIBLE,Display.DEFAULT_DISPLAY, mContentInsets, mInputChannel);

    3).mInputEventReceiver = new WallpaperInputEventReceiver(mInputChannel, Looper.myLooper());

    4).mSession.relayout(mWindow, mWindow.mSeq, mLayout, mWidth, mHeight,View.VISIBLE, 0, mWinFrame, mOverscanInsets, mContentInsets, mVisibleInsets, mConfiguration, mSurfaceHolder.mSurface);

    5).mSurfaceHolder.setSurfaceFrameSize(w, h);

    6).onSurfaceCreated(mSurfaceHolder);

    7).onSurfaceChanged(mSurfaceHolder, mFormat, mCurWidth, mCurHeight);   drawFrame();

    8).onSurfaceRedrawNeeded(mSurfaceHolder);   drawFrame();

    9)onVisibilityChanged(true);   drawFrame();

3.MSG_UPDATE_SURFACE

a.mEngine.updateSurface(true, false, false)

    1).mSession.relayout(mWindow, mWindow.mSeq, mLayout, mWidth, mHeight,View.VISIBLE, 0, mWinFrame, mOverscanInsets, mContentInsets, mVisibleInsets, mConfiguration, mSurfaceHolder.mSurface);

    2).mSurfaceHolder.setSurfaceFrameSize(w, h);

4.MSG_WINDOW_RESIZED

a.mEngine.updateSurface(true, false, reportDraw);

    1).mSession.relayout(mWindow, mWindow.mSeq, mLayout, mWidth, mHeight,View.VISIBLE, 0, mWinFrame, mOverscanInsets, mContentInsets, mVisibleInsets, mConfiguration, mSurfaceHolder.mSurface);

    2).mSurfaceHolder.setSurfaceFrameSize(w, h);

    3).onSurfaceRedrawNeeded(mSurfaceHolder);

    4)mSession.finishDrawing(mWindow);

b.mEngine.doOffsetsChanged(true);----------没做什么;

总结:从上面的逻辑看,壁纸这块逻辑代码写的比较乱。


本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?立即注册

x
回复 支持 反对

使用道具 举报

1198

主题

2060

帖子

7058

积分

超级版主

Rank: 8Rank: 8

积分
7058
板凳
 楼主| 发表于 2016-5-2 23:50:55 | 只看该作者
最后的解决方法是修改WallpaperService.java这个文件:
        void updateSurface(boolean forceRelayout, boolean forceReport, boolean redrawNeeded) {
                        Log.w("zcfdebug", "updateSurface in WallpaperService!");
            if (mDestroyed) {
                Log.w(TAG, "Ignoring updateSurface: destroyed");
            }

            boolean fixedSize = false;
            int myWidth = mSurfaceHolder.getRequestedWidth();
            if (myWidth <= 0) myWidth = ViewGroup.LayoutParams.MATCH_PARENT;
            else fixedSize = true;
            int myHeight = mSurfaceHolder.getRequestedHeight();
            if (myHeight <= 0) myHeight = ViewGroup.LayoutParams.MATCH_PARENT;
            else fixedSize = true;

            final boolean creating = !mCreated;
            final boolean surfaceCreating = !mSurfaceCreated;
            final boolean formatChanged = mFormat != mSurfaceHolder.getRequestedFormat();
            boolean sizeChanged = mWidth != myWidth || mHeight != myHeight;
            boolean insetsChanged = !mCreated;
            final boolean typeChanged = mType != mSurfaceHolder.getRequestedType();
            final boolean flagsChanged = mCurWindowFlags != mWindowFlags ||
                    mCurWindowPrivateFlags != mWindowPrivateFlags;
            if (forceRelayout || creating || surfaceCreating || formatChanged || sizeChanged
                    || typeChanged || flagsChanged || redrawNeeded
                    || !mIWallpaperEngine.mShownReported) {

                if (DEBUG) Log.v(TAG, "Changes: creating=" + creating
                        + " format=" + formatChanged + " size=" + sizeChanged);

                try {
                    mWidth = myWidth;
                    mHeight = myHeight;
                    mFormat = mSurfaceHolder.getRequestedFormat();
                    mType = mSurfaceHolder.getRequestedType();

                    mLayout.x = 0;
                    mLayout.y = 0;
//zcfdebug++<<
                    mLayout.x = 0;
                    mLayout.y = 260;
//zcfdebug>>++
                    mLayout.width = myWidth;
                    mLayout.height = myHeight;
                                        mLayout.height = 560;        //zcfdebug++
                    
                    mLayout.format = mFormat;
                    
                    mCurWindowFlags = mWindowFlags;
                    mLayout.flags = mWindowFlags
                            | WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS
                            | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
                            | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
                            ;
                    mCurWindowPrivateFlags = mWindowPrivateFlags;
                    mLayout.privateFlags = mWindowPrivateFlags;

                    mLayout.memoryType = mType;
                    mLayout.token = mWindowToken;

                    if (!mCreated) {
                        // Retrieve watch round and outset info
                        final WindowManager windowService = (WindowManager)getSystemService(
                                Context.WINDOW_SERVICE);
                        TypedArray windowStyle = obtainStyledAttributes(
                                com.android.internal.R.styleable.Window);
                        final Display display = windowService.getDefaultDisplay();
                        final boolean shouldUseBottomOutset =
                                display.getDisplayId() == Display.DEFAULT_DISPLAY;
                        if (shouldUseBottomOutset && windowStyle.hasValue(
                                R.styleable.Window_windowOutsetBottom)) {
                            if (mOutsetBottom == null) mOutsetBottom = new TypedValue();
                            windowStyle.getValue(R.styleable.Window_windowOutsetBottom,
                                    mOutsetBottom);
                        } else {
                            mOutsetBottom = null;
                        }
                        mWindowIsRound = getResources().getBoolean(
                                com.android.internal.R.bool.config_windowIsRound);
                        windowStyle.recycle();

                        // detect emulator
                        mIsEmulator = Build.HARDWARE.contains("goldfish");
                        mIsCircularEmulator = SystemProperties.getBoolean(
                               ViewRootImpl.PROPERTY_EMULATOR_CIRCULAR, false);
                        // mIsCircularEmulator = false;  // @todo L-MARK by  ViewRootImpl.PROPERTY_EMULATOR_CIRCULAR is private

                        // Add window
                        mLayout.type = mIWallpaperEngine.mWindowType;
                        mLayout.gravity = Gravity.START|Gravity.TOP;
                        mLayout.setTitle(WallpaperService.this.getClass().getName());
                        mLayout.windowAnimations =
                                com.android.internal.R.style.Animation_Wallpaper;
                        mInputChannel = new InputChannel();
                        if (mSession.addToDisplay(mWindow, mWindow.mSeq, mLayout, View.VISIBLE,
                            Display.DEFAULT_DISPLAY, mContentInsets, mInputChannel) < 0) {
                            Log.w(TAG, "Failed to add window while updating wallpaper surface.");
                            return;
                        }
                        mCreated = true;

                        mInputEventReceiver = new WallpaperInputEventReceiver(
                                mInputChannel, Looper.myLooper());
                    }
                    
                    mSurfaceHolder.mSurfaceLock.lock();
                    mDrawingAllowed = true;

                    if (!fixedSize) {
                        mLayout.surfaceInsets.set(mIWallpaperEngine.mDisplayPadding);
                    } else {
                        mLayout.surfaceInsets.set(0, 0, 0, 0);
                    }
                                        mHeight=560;//zcfdebug++
                    final int relayoutResult = mSession.relayout(
                        mWindow, mWindow.mSeq, mLayout, mWidth, mHeight,
                            View.VISIBLE, 0, mWinFrame, mOverscanInsets, mContentInsets,
                            mVisibleInsets, mStableInsets, mConfiguration, mSurfaceHolder.mSurface);

                    if (DEBUG) Log.v(TAG, "New surface: " + mSurfaceHolder.mSurface
                            + ", frame=" + mWinFrame);
                    
                    int w = mWinFrame.width();
                    int h = mWinFrame.height();

                    if (!fixedSize) {
                        final Rect padding = mIWallpaperEngine.mDisplayPadding;
                        w += padding.left + padding.right;
                        h += padding.top + padding.bottom;
                        mOverscanInsets.left += padding.left;
                        mOverscanInsets.top += padding.top;
                        mOverscanInsets.right += padding.right;
                        mOverscanInsets.bottom += padding.bottom;
                        mContentInsets.left += padding.left;
                        mContentInsets.top += padding.top;
                        mContentInsets.right += padding.right;
                        mContentInsets.bottom += padding.bottom;
                        mStableInsets.left += padding.left;
                        mStableInsets.top += padding.top;
                        mStableInsets.right += padding.right;
                        mStableInsets.bottom += padding.bottom;
                    }

                    if (mCurWidth != w) {
                        sizeChanged = true;
                        mCurWidth = w;
                    }
                    if (mCurHeight != h) {
                        sizeChanged = true;
                        mCurHeight = h;
                    }

                    insetsChanged |= !mDispatchedOverscanInsets.equals(mOverscanInsets);
                    insetsChanged |= !mDispatchedContentInsets.equals(mContentInsets);
                    insetsChanged |= !mDispatchedStableInsets.equals(mStableInsets);

                    mSurfaceHolder.setSurfaceFrameSize(w, h);
                    mSurfaceHolder.mSurfaceLock.unlock();

                    if (!mSurfaceHolder.mSurface.isValid()) {
                        reportSurfaceDestroyed();
                        if (DEBUG) Log.v(TAG, "Layout: Surface destroyed");
                        return;
                    }

                    boolean didSurface = false;

                    try {
                        mSurfaceHolder.ungetCallbacks();

                        if (surfaceCreating) {
                            mIsCreating = true;
                            didSurface = true;
                            if (DEBUG) Log.v(TAG, "onSurfaceCreated("
                                    + mSurfaceHolder + "): " + this);
                            onSurfaceCreated(mSurfaceHolder);
                            SurfaceHolder.Callback callbacks[] = mSurfaceHolder.getCallbacks();
                            if (callbacks != null) {
                                for (SurfaceHolder.Callback c : callbacks) {
                                    c.surfaceCreated(mSurfaceHolder);
                                }
                            }
                        }

                        redrawNeeded |= creating || (relayoutResult
                                & WindowManagerGlobal.RELAYOUT_RES_FIRST_TIME) != 0;

                        if (forceReport || creating || surfaceCreating
                                || formatChanged || sizeChanged) {
                            if (DEBUG) {
                                RuntimeException e = new RuntimeException();
                                e.fillInStackTrace();
                                Log.w(TAG, "forceReport=" + forceReport + " creating=" + creating
                                        + " formatChanged=" + formatChanged
                                        + " sizeChanged=" + sizeChanged, e);
                            }
                            if (DEBUG) Log.v(TAG, "onSurfaceChanged("
                                    + mSurfaceHolder + ", " + mFormat
                                    + ", " + mCurWidth + ", " + mCurHeight
                                    + "): " + this);
                            didSurface = true;
                            onSurfaceChanged(mSurfaceHolder, mFormat,
                                    mCurWidth, mCurHeight);
                            SurfaceHolder.Callback callbacks[] = mSurfaceHolder.getCallbacks();
                            if (callbacks != null) {
                                for (SurfaceHolder.Callback c : callbacks) {
                                    c.surfaceChanged(mSurfaceHolder, mFormat,
                                            mCurWidth, mCurHeight);
                                }
                            }
                        }

                        if (insetsChanged) {
                            mDispatchedOverscanInsets.set(mOverscanInsets);
                            mDispatchedContentInsets.set(mContentInsets);
                            mDispatchedStableInsets.set(mStableInsets);
                            final boolean isRound = (mIsEmulator && mIsCircularEmulator)
                                    || mWindowIsRound;
                            mFinalSystemInsets.set(mDispatchedOverscanInsets);
                            mFinalStableInsets.set(mDispatchedStableInsets);
                            if (mOutsetBottom != null) {
                                final DisplayMetrics metrics = getResources().getDisplayMetrics();
                                mFinalSystemInsets.bottom =
                                        ( (int) mOutsetBottom.getDimension(metrics) )
                                        + mIWallpaperEngine.mDisplayPadding.bottom;
                            }
                            WindowInsets insets = new WindowInsets(mFinalSystemInsets,
                                    null, mFinalStableInsets, isRound);
                            onApplyWindowInsets(insets);
                        }

                        if (redrawNeeded) {
                            onSurfaceRedrawNeeded(mSurfaceHolder);
                            SurfaceHolder.Callback callbacks[] = mSurfaceHolder.getCallbacks();
                            if (callbacks != null) {
                                for (SurfaceHolder.Callback c : callbacks) {
                                    if (c instanceof SurfaceHolder.Callback2) {
                                        ((SurfaceHolder.Callback2)c).surfaceRedrawNeeded(
                                                mSurfaceHolder);
                                    }
                                }
                            }
                        }

                        if (didSurface && !mReportedVisible) {
                            // This wallpaper is currently invisible, but its
                            // surface has changed.  At this point let's tell it
                            // again that it is invisible in case the report about
                            // the surface caused it to start running.  We really
                            // don't want wallpapers running when not visible.
                            if (mIsCreating) {
                                // Some wallpapers will ignore this call if they
                                // had previously been told they were invisble,
                                // so if we are creating a new surface then toggle
                                // the state to get them to notice.
                                if (DEBUG) Log.v(TAG, "onVisibilityChanged(true) at surface: "
                                        + this);
                                onVisibilityChanged(true);
                            }
                            if (DEBUG) Log.v(TAG, "onVisibilityChanged(false) at surface: "
                                        + this);
                            onVisibilityChanged(false);
                        }

                    } finally {
                        mIsCreating = false;
                        mSurfaceCreated = true;
                        if (redrawNeeded) {
                            mSession.finishDrawing(mWindow);
                        }
                        mIWallpaperEngine.reportShown();
                    }
                } catch (RemoteException ex) {
                }
                if (DEBUG) Log.v(
                    TAG, "Layout: x=" + mLayout.x + " y=" + mLayout.y +
                    " w=" + mLayout.width + " h=" + mLayout.height);
            }
        }
        
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

Archiver|手机版|小黑屋|Comsenz Inc.

GMT+8, 2025-12-15 02:02 , Processed in 0.027798 second(s), 8 queries , Apc On.

Powered by Discuz! X3.2

© 2001-2013 Comsenz Inc.

快速回复 返回顶部 返回列表