Android窗口化app位移

强制移动window窗口可以通过在PhoneWindowManager中强制指定window的显示区域即可, 但我需要的是一个有过渡动画的位移.

查找相关代码发现窗口动画有一个位移的函数:

|–frameworks/base/server/java/com/android/server/wm/WindowManagerService.java

 // "Something has changed!  Let's make it correct now."
    private final void performLayoutAndPlaceSurfacesLockedInner(boolean recoveringMemory) {
...
if (w.mHasSurface && w.shouldAnimateMove()) {
                        // Frame has moved, containing content frame
                        // has also moved, and we're not currently animating...
                        // let's do something.
                        Animation a = AnimationUtils.loadAnimation(mContext,
                                com.android.internal.R.anim.window_move_from_decor);
                        winAnimator.setAnimation(a);
                        winAnimator.mAnimDw = w.mLastFrame.left - w.mFrame.left;
                        winAnimator.mAnimDh = w.mLastFrame.top - w.mFrame.top;
                        try {
                            w.mClient.moved(w.mFrame.left, w.mFrame.top);
                        } catch (RemoteException e) {
                        }
                    }
...
}

|–frameworks/base/core/java/android/view/ViewRootImpl.java

static class W extends IWindow.Stub {
        ...
        @Override
        public void moved(int newX, int newY) {
            final ViewRootImpl viewAncestor = mViewAncestor.get();
            if (viewAncestor != null) {
                viewAncestor.dispatchMoved(newX, newY);
            }
        }
...
}
    public void dispatchMoved(int newX, int newY) {
        if (DEBUG_LAYOUT) Log.v(TAG, "Window moved " + this + ": newX=" + newX + " newY=" + newY);
        if (mTranslator != null) {
            PointF point = new PointF(newX, newY);
            mTranslator.translatePointInScreenToAppWindow(point);
            newX = (int) (point.x + 0.5);
            newY = (int) (point.y + 0.5);
        }
        Message msg = mHandler.obtainMessage(MSG_WINDOW_MOVED, newX, newY);
        mHandler.sendMessage(msg);
    }
    
...
case MSG_WINDOW_MOVED:
                if (mAdded) {
                    final int w = mWinFrame.width();
                    final int h = mWinFrame.height();
                    final int l = msg.arg1;
                    final int t = msg.arg2;
                    mWinFrame.left = l;
                    mWinFrame.right = l + w;
                    mWinFrame.top = t;
                    mWinFrame.bottom = t + h;

                    if (mView != null) {
                        forceLayout(mView);
                    }
                    requestLayout();
                }
                break;
...

private void performTraversals() {}
->WindowManagerService.relayoutWindow().
->WindowManagerService.performLayoutAndPlaceSurfacesLocked().

|–frameworks/base/service/java/com/android/server/wm/WindowState.java

/**
     * Return whether this window is wanting to have a translation
     * animation applied to it for an in-progress move.  (Only makes
     * sense to call from performLayoutAndPlaceSurfacesLockedInner().)
     */
    boolean shouldAnimateMove() {
//有可能不满足的一个条件
        return mContentChanged && !mExiting && !mWinAnimator.mLastHidden && mService.okToDisplay()
                && (mFrame.top != mLastFrame.top
                        || mFrame.left != mLastFrame.left)
                && (mAttrs.privateFlags&PRIVATE_FLAG_NO_MOVE_ANIMATION) == 0
                && (mAttachedWindow == null || !mAttachedWindow.shouldAnimateMove());
    }

    @Override
    public void computeFrameLw(Rect pf, Rect df, Rect of, Rect cf, Rect vf, Rect dcf) {
        ...
        if (!mParentFrame.equals(pf)) {
            //Slog.i(TAG, "Window " + this + " content frame from " + mParentFrame
            //        + " to " + pf);
            mParentFrame.set(pf);
            mContentChanged = true;
        }
   ...
}

//也就是说, 只需要pf的值变化, 即可触发.

|–frameworks/base/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java

//转了一圈还是回到了这里.
    /** {@inheritDoc} */
    @Override
    public void layoutWindowLw(WindowState win, WindowManager.LayoutParams attrs,
            WindowState attached) {
        ...
		//AnsonCode 2016.12.21
		String mapPkg = "com.autonavi.amapauto";
		if(mapPkg.equals(attrs.packageName) && deadareaSide > 0){
/****** resolution 1 
			//pf parentFrame
			//vf visibleFrame
			//df displayFrame
			//cf contentFrame
			//of overScanFrame
			//dcf decorContentFrame
************/

/******** resolution 2 ************/
			//0:off; 5:left; 6:right
			int offset = 480;
			String b = pf.toShortString();
			if(deadareaSide == 5){
				pf.left  += offset;
				pf.right += offset;
			}else if(deadareaSide == 6){
				pf.left  -= offset;
				pf.right -= offset;
			}
			Log.d("ALog", "PhoneWindowManager.layoutWindowLw pfBefore(" + b + "): pfAfter(" + pf.toShortString() + ")");
		}
        win.computeFrameLw(pf, df, of, cf, vf, dcf);

        // Dock windows carve out the bottom of the screen, so normal windows
        // can't appear underneath them.
        if (attrs.type == TYPE_INPUT_METHOD && win.isVisibleOrBehindKeyguardLw()
                && !win.getGivenInsetsPendingLw()) {
            setLastInputMethodWindowLw(null, null);
            offsetInputMethodWindowLw(win);
        }
    }

OK, 完成

测试流程如下:

新增APP并把主题设置为Theme.Halo.Dialog.

APP打开后会显示在屏幕中间;

通过发送广播告诉PhoneWindowManager, 去修改pf的值.

带过渡动画的位移实现.

    原文作者:ansondroider
    原文地址: https://blog.csdn.net/ansondroider/article/details/53893695
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞