当前位置:  编程技术>移动开发
本页文章导读:
    ▪四个方向下的SlidingDrawer        四个方向上的SlidingDrawer http://blog.sephiroth.it/2011/03/29/widget-slidingdrawer-top-to-bottom/ /* * Copyright (C) 2008 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not u.........
    ▪ Wireshark抓包工具-干爬虫必备        Wireshark抓包工具--做爬虫必备   ......
    ▪ 保护模式准备知识-书中boot.asm代码详细注释       保护模式预备知识--书中boot.asm代码详细注释一、FAT12软盘格式        软盘格式如图1:        每个扇区是512字节,512B*2880=1.44MB                                                 图 1 .........

[1]四个方向下的SlidingDrawer
    来源: 互联网  发布时间: 2014-02-18
四个方向上的SlidingDrawer
http://blog.sephiroth.it/2011/03/29/widget-slidingdrawer-top-to-bottom/

/*
 * Copyright (C) 2008 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * 
 * Modifications by: Alessandro Crugnola
 */

package it.sephiroth.demo.slider.widget;

import it.sephiroth.demo.slider.R;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Rect;
import android.os.Handler;
import android.os.Message;
import android.os.SystemClock;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.SoundEffectConstants;
import android.view.VelocityTracker;
import android.view.View;
import android.view.ViewGroup;
import android.view.accessibility.AccessibilityEvent;


public class MultiDirectionSlidingDrawer extends ViewGroup {
	
	public static final int				ORIENTATION_RTL		= 0;
	public static final int				ORIENTATION_BTT		= 1;
	public static final int				ORIENTATION_LTR		= 2;
	public static final int				ORIENTATION_TTB		= 3;
	
	private static final int			TAP_THRESHOLD					= 6;
	private static final float			MAXIMUM_TAP_VELOCITY			= 100.0f;
	private static final float			MAXIMUM_MINOR_VELOCITY		= 150.0f;
	private static final float			MAXIMUM_MAJOR_VELOCITY		= 200.0f;
	private static final float			MAXIMUM_ACCELERATION			= 2000.0f;
	private static final int			VELOCITY_UNITS					= 1000;
	private static final int			MSG_ANIMATE						= 1000;
	private static final int			ANIMATION_FRAME_DURATION	= 1000 / 60;
	
	private static final int			EXPANDED_FULL_OPEN			= -10001;
	private static final int			COLLAPSED_FULL_CLOSED		= -10002;
	
	private final int						mHandleId;
	private final int						mContentId;
	
	private View							mHandle;
	private View							mContent;
	
	private final Rect					mFrame							= new Rect();
	private final Rect					mInvalidate						= new Rect();
	private boolean						mTracking;
	private boolean						mLocked;
	
	private VelocityTracker				mVelocityTracker;
	
	private boolean						mInvert;
	private boolean						mVertical;
	private boolean						mExpanded;
	private int								mBottomOffset;
	private int								mTopOffset;
	private int								mHandleHeight;
	private int								mHandleWidth;
	
	private OnDrawerOpenListener		mOnDrawerOpenListener;
	private OnDrawerCloseListener		mOnDrawerCloseListener;
	private OnDrawerScrollListener	mOnDrawerScrollListener;
	
	private final Handler				mHandler							= new SlidingHandler();
	private float							mAnimatedAcceleration;
	private float							mAnimatedVelocity;
	private float							mAnimationPosition;
	private long							mAnimationLastTime;
	private long							mCurrentAnimationTime;
	private int								mTouchDelta;
	private boolean						mAnimating;
	private boolean						mAllowSingleTap;
	private boolean						mAnimateOnClick;
	
	private final int						mTapThreshold;
	private final int						mMaximumTapVelocity;
	private int								mMaximumMinorVelocity;
	private int								mMaximumMajorVelocity;
	private int								mMaximumAcceleration;
	private final int						mVelocityUnits;
	
	/**
	 * Callback invoked when the drawer is opened.
	 */
	public static interface OnDrawerOpenListener {
		
		/**
		 * Invoked when the drawer becomes fully open.
		 */
		public void onDrawerOpened();
	}
	
	/**
	 * Callback invoked when the drawer is closed.
	 */
	public static interface OnDrawerCloseListener {
		
		/**
		 * Invoked when the drawer becomes fully closed.
		 */
		public void onDrawerClosed();
	}
	
	/**
	 * Callback invoked when the drawer is scrolled.
	 */
	public static interface OnDrawerScrollListener {
		
		/**
		 * Invoked when the user starts dragging/flinging the drawer's handle.
		 */
		public void onScrollStarted();
		
		/**
		 * Invoked when the user stops dragging/flinging the drawer's handle.
		 */
		public void onScrollEnded();
	}
	
	/**
	 * Creates a new SlidingDrawer from a specified set of attributes defined in
	 * XML.
	 * 
	 * @param context
	 *           The application's environment.
	 * @param attrs
	 *           The attributes defined in XML.
	 */
	public MultiDirectionSlidingDrawer( Context context, AttributeSet attrs )
	{
		this( context, attrs, 0 );
	}
	
	/**
	 * Creates a new SlidingDrawer from a specified set of attributes defined in
	 * XML.
	 * 
	 * @param context
	 *           The application's environment.
	 * @param attrs
	 *           The attributes defined in XML.
	 * @param defStyle
	 *           The style to apply to this widget.
	 */
	public MultiDirectionSlidingDrawer( Context context, AttributeSet attrs, int defStyle )
	{
		super( context, attrs, defStyle );
		TypedArray a = context.obtainStyledAttributes( attrs, R.styleable.MultiDirectionSlidingDrawer, defStyle, 0 );
		
		int orientation = a.getInt( R.styleable.MultiDirectionSlidingDrawer_direction, ORIENTATION_BTT );
		mVertical = ( orientation == ORIENTATION_BTT || orientation == ORIENTATION_TTB );
		mBottomOffset = (int)a.getDimension( R.styleable.MultiDirectionSlidingDrawer_bottomOffset, 0.0f );
		mTopOffset = (int)a.getDimension( R.styleable.MultiDirectionSlidingDrawer_topOffset, 0.0f );
		mAllowSingleTap = a.getBoolean( R.styleable.MultiDirectionSlidingDrawer_allowSingleTap, true );
		mAnimateOnClick = a.getBoolean( R.styleable.MultiDirectionSlidingDrawer_animateOnClick, true );
		mInvert = ( orientation == ORIENTATION_TTB || orientation == ORIENTATION_LTR );
		
		int handleId = a.getResourceId( R.styleable.MultiDirectionSlidingDrawer_handle, 0 );
		if ( handleId == 0 ) { throw new IllegalArgumentException( "The handle attribute is required and must refer "
				+ "to a valid child." ); }
		
		int contentId = a.getResourceId( R.styleable.MultiDirectionSlidingDrawer_content, 0 );
		if ( contentId == 0 ) { throw new IllegalArgumentException( "The content attribute is required and must refer "
				+ "to a valid child." ); }
		
		if ( handleId == contentId ) { throw new IllegalArgumentException( "The content and handle attributes must refer "
				+ "to different children." ); }
		mHandleId = handleId;
		mContentId = contentId;
		
		final float density = getResources().getDisplayMetrics().density;
		mTapThreshold = (int)( TAP_THRESHOLD * density + 0.5f );
		mMaximumTapVelocity = (int)( MAXIMUM_TAP_VELOCITY * density + 0.5f );
		mMaximumMinorVelocity = (int)( MAXIMUM_MINOR_VELOCITY * density + 0.5f );
		mMaximumMajorVelocity = (int)( MAXIMUM_MAJOR_VELOCITY * density + 0.5f );
		mMaximumAcceleration = (int)( MAXIMUM_ACCELERATION * density + 0.5f );
		mVelocityUnits = (int)( VELOCITY_UNITS * density + 0.5f );
		
		if( mInvert ) {
			mMaximumAcceleration = -mMaximumAcceleration;
			mMaximumMajorVelocity = -mMaximumMajorVelocity;
			mMaximumMinorVelocity = -mMaximumMinorVelocity;
		}
		
		a.recycle();
		setAlwaysDrawnWithCacheEnabled( false );
	}
	
	@Override
	protected void onFinishInflate()
	{
		mHandle = findViewById( mHandleId );
		if ( mHandle == null ) { throw new IllegalArgumentException( "The handle attribute is must refer to an" + " existing child." ); }
		mHandle.setOnClickListener( new DrawerToggler() );
		
		mContent = findViewById( mContentId );
		if ( mContent == null ) { throw new IllegalArgumentException( "The content attribute is must refer to an"
				+ " existing child." ); }
		mContent.setVisibility( View.GONE );
	}
	
	@Override
	protected void onMeasure( int widthMeasureSpec, int heightMeasureSpec )
	{
		int widthSpecMode = MeasureSpec.getMode( widthMeasureSpec );
		int widthSpecSize = MeasureSpec.getSize( widthMeasureSpec );
		
		int heightSpecMode = MeasureSpec.getMode( heightMeasureSpec );
		int heightSpecSize = MeasureSpec.getSize( heightMeasureSpec );
		
		if ( widthSpecMode == MeasureSpec.UNSPECIFIED || heightSpecMode == MeasureSpec.UNSPECIFIED ) { throw new RuntimeException(
				"SlidingDrawer cannot have UNSPECIFIED dimensions" ); }
		
		final View handle = mHandle;
		measureChild( handle, widthMeasureSpec, heightMeasureSpec );
		
		if ( mVertical ) {
			int height = heightSpecSize - handle.getMeasuredHeight() - mTopOffset;
			mContent.measure( MeasureSpec.makeMeasureSpec( widthSpecSize, MeasureSpec.EXACTLY ), MeasureSpec.makeMeasureSpec( height, MeasureSpec.EXACTLY ) );
		} else {
			int width = widthSpecSize - handle.getMeasuredWidth() - mTopOffset;
			mContent.measure( MeasureSpec.makeMeasureSpec( width, MeasureSpec.EXACTLY ), MeasureSpec.makeMeasureSpec( heightSpecSize, MeasureSpec.EXACTLY ) );
		}
		
		setMeasuredDimension( widthSpecSize, heightSpecSize );
	}
	
	@Override
	protected void dispatchDraw( Canvas canvas )
	{
		final long drawingTime = getDrawingTime();
		final View handle = mHandle;
		final boolean isVertical = mVertical;
		
		drawChild( canvas, handle, drawingTime );
		
		if ( mTracking || mAnimating ) {
			final Bitmap cache = mContent.getDrawingCache();
			if ( cache != null ) {
				if ( isVertical ) {
					if( mInvert ) {
						canvas.drawBitmap( cache, 0, handle.getTop() - (getBottom() - getTop()) + mHandleHeight, null );
					} else {
						canvas.drawBitmap( cache, 0, handle.getBottom(), null );
					}
				} else {
					canvas.drawBitmap( cache, mInvert ? handle.getLeft() - cache.getWidth() : handle.getRight(), 0, null );
				}
			} else {
				canvas.save();
				if( mInvert ) {
					canvas.translate( isVertical ? 0 : handle.getLeft() - mTopOffset - mContent.getMeasuredWidth(), isVertical ? handle.getTop() - mTopOffset - mContent.getMeasuredHeight() : 0 );
				} else {
					canvas.translate( isVertical ? 0 : handle.getLeft() - mTopOffset, isVertical ? handle.getTop() - mTopOffset : 0 );
				}
				drawChild( canvas, mContent, drawingTime );
				canvas.restore();
			}
			invalidate();
		} else if ( mExpanded ) {
			drawChild( canvas, mContent, drawingTime );
		}
	}
	
	public static final String	LOG_TAG	= "Sliding";
	
	@Override
	protected void onLayout( boolean changed, int l, int t, int r, int b )
	{
		if ( mTracking ) { return; }
		
		final int width = r - l;
		final int height = b - t;
		
		final View handle = mHandle;
		
		int handleWidth = handle.getMeasuredWidth();
		int handleHeight = handle.getMeasuredHeight();
		
		Log.d( LOG_TAG, "handleHeight: " + handleHeight );
		
		int handleLeft;
		int handleTop;
		
		final View content = mContent;
		
		if ( mVertical ) {
			handleLeft = ( width - handleWidth ) / 2;
			if ( mInvert ) {
				Log.d( LOG_TAG, "content.layout(1)" );
				handleTop = mExpanded ? height - mBottomOffset - handleHeight : mTopOffset;
				content.layout( 0, mTopOffset, content.getMeasuredWidth(), mTopOffset + content.getMeasuredHeight() );
			} else {
				handleTop = mExpanded ? mTopOffset : height - handleHeight + mBottomOffset;
				content.layout( 0, mTopOffset + handleHeight, content.getMeasuredWidth(), mTopOffset + handleHeight + content.getMeasuredHeight() );
			}
		} else {
			handleTop = ( height - handleHeight ) / 2;
			if( mInvert ) {
				handleLeft = mExpanded ? width - mBottomOffset - handleWidth : mTopOffset;
				content.layout( mTopOffset, 0, mTopOffset + content.getMeasuredWidth(), content.getMeasuredHeight() );
			} else {
				handleLeft = mExpanded ? mTopOffset : width - handleWidth + mBottomOffset;
				content.layout( mTopOffset + handleWidth, 0, mTopOffset + handleWidth + content.getMeasuredWidth(), content.getMeasuredHeight() );
			}
		}
		
		handle.layout( handleLeft, handleTop, handleLeft + handleWidth, handleTop + handleHeight );
		mHandleHeight = handle.getHeight();
		mHandleWidth = handle.getWidth();
	}
	
	@Override
	public boolean onInterceptTouchEvent( MotionEvent event )
	{
		if ( mLocked ) { return false; }
		
		final int action = event.getAction();
		
		float x = event.getX();
		float y = event.getY();
		
		final Rect frame = mFrame;
		final View handle = mHandle;
		
		handle.getHitRect( frame );
		if ( !mTracking && !frame.contains( (int)x, (int)y ) ) { return false; }
		
		if ( action == MotionEvent.ACTION_DOWN ) {
			mTracking = true;
			
			handle.setPressed( true );
			// Must be called before prepareTracking()
			prepareContent();
			
			// Must be called after prepareContent()
			if ( mOnDrawerScrollListener != null ) {
				mOnDrawerScrollListener.onScrollStarted();
			}
			
			if ( mVertical ) {
				final int top = mHandle.getTop();
				mTouchDelta = (int)y - top;
				prepareTracking( top );
			} else {
				final int left = mHandle.getLeft();
				mTouchDelta = (int)x - left;
				prepareTracking( left );
			}
			mVelocityTracker.addMovement( event );
		}
		
		return true;
	}
	
	@Override
	public boolean onTouchEvent( MotionEvent event )
	{
		if ( mLocked ) { return true; }
		
		if ( mTracking ) {
			mVelocityTracker.addMovement( event );
			final int action = event.getAction();
			switch ( action ) {
				case MotionEvent.ACTION_MOVE:
					moveHandle( (int)( mVertical ? event.getY() : event.getX() ) - mTouchDelta );
					break;
				case MotionEvent.ACTION_UP:
				case MotionEvent.ACTION_CANCEL: {
					final VelocityTracker velocityTracker = mVelocityTracker;
					velocityTracker.computeCurrentVelocity( mVelocityUnits );
					
					float yVelocity = velocityTracker.getYVelocity();
					float xVelocity = velocityTracker.getXVelocity();
					boolean negative;
					
					final boolean vertical = mVertical;
					if ( vertical ) {
						negative = yVelocity < 0;
						if ( xVelocity < 0 ) {
							xVelocity = -xVelocity;
						}
						// fix by Maciej Ciemięga.
						if ( (!mInvert && xVelocity > mMaximumMinorVelocity) || (mInvert && xVelocity < mMaximumMinorVelocity) ) {
							xVelocity = mMaximumMinorVelocity;
						}
					} else {
						negative = xVelocity < 0;
						if ( yVelocity < 0 ) {
							yVelocity = -yVelocity;
						}
						// fix by Maciej Ciemięga.
						if ( (!mInvert && yVelocity > mMaximumMinorVelocity) || (mInvert && yVelocity < mMaximumMinorVelocity) ) {
							yVelocity = mMaximumMinorVelocity;
						}
					}
					
					float velocity = (float)Math.hypot( xVelocity, yVelocity );
					if ( negative ) {
						velocity = -velocity;
					}
					
					final int handleTop = mHandle.getTop();
					final int handleLeft = mHandle.getLeft();
					final int handleBottom = mHandle.getBottom();
					final int handleRight = mHandle.getRight();
					
					if ( Math.abs( velocity ) < mMaximumTapVelocity ) {
						boolean c1;
						boolean c2;
						boolean c3;
						boolean c4;
						
						if( mInvert ) {
							c1 = ( mExpanded && (getBottom() - handleBottom ) < mTapThreshold + mBottomOffset );
							c2 = ( !mExpanded && handleTop < mTopOffset + mHandleHeight - mTapThreshold );
							c3 = ( mExpanded && (getRight() - handleRight ) < mTapThreshold + mBottomOffset );
							c4 = ( !mExpanded && handleLeft > mTopOffset + mHandleWidth + mTapThreshold );
						} else {
							c1 = ( mExpanded && handleTop < mTapThreshold + mTopOffset );
							c2 = ( !mExpanded && handleTop > mBottomOffset + getBottom() - getTop() - mHandleHeight - mTapThreshold );
							c3 = ( mExpanded && handleLeft < mTapThreshold + mTopOffset );
							c4 = ( !mExpanded && handleLeft > mBottomOffset + getRight() - getLeft() - mHandleWidth - mTapThreshold );
						}
						
						Log.d( LOG_TAG, "ACTION_UP: " + "c1: " + c1 + ", c2: " + c2 + ", c3: " + c3 + ", c4: " + c4 );
						
						if ( vertical ? c1 || c2 : c3 || c4 ) {
							
							if ( mAllowSingleTap ) {
								playSoundEffect( SoundEffectConstants.CLICK );
								
								if ( mExpanded ) {
									animateClose( vertical ? handleTop : handleLeft );
								} else {
									animateOpen( vertical ? handleTop : handleLeft );
								}
							} else {
								performFling( vertical ? handleTop : handleLeft, velocity, false );
							}
						} else {
							performFling( vertical ? handleTop : handleLeft, velocity, false );
						}
					} else {
						performFling( vertical ? handleTop : handleLeft, velocity, false );
					}
				}
					break;
			}
		}
		
		return mTracking || mAnimating || super.onTouchEvent( event );
	}
	
	private void animateClose( int position )
	{
		prepareTracking( position );
		performFling( position, mMaximumAcceleration, true );
	}
	
	private void animateOpen( int position )
	{
		prepareTracking( position );
		performFling( position, -mMaximumAcceleration, true );
	}
	
	private void performFling( int position, float velocity, boolean always )
	{
		mAnimationPosition = position;
		mAnimatedVelocity = velocity;
		
		boolean c1;
		boolean c2;
		boolean c3;
		
		if ( mExpanded ) 
		{
			int bottom = mVertical ? getBottom() : getRight();
			int handleHeight = mVertical ? mHandleHeight : mHandleWidth;
			
			Log.d( LOG_TAG, "position: " + position + ", velocity: " + velocity + ", mMaximumMajorVelocity: " + mMaximumMajorVelocity );
			c1 = mInvert ? velocity < mMaximumMajorVelocity : velocity > mMaximumMajorVelocity;
			c2 = mInvert ? ( bottom - (position + handleHeight) ) + mBottomOffset > handleHeight : position > mTopOffset + ( mVertical ? mHandleHeight : mHandleWidth );
			c3 = mInvert ? velocity < -mMaximumMajorVelocity : velocity > -mMaximumMajorVelocity;
			Log.d( LOG_TAG, "EXPANDED. c1: " + c1 + ", c2: " + c2 + ", c3: " + c3 );
			if ( always || ( c1 || ( c2 && c3 ) ) ) {
				// We are expanded, So animate to CLOSE!
				mAnimatedAcceleration = mMaximumAcceleration;
				if( mInvert )
				{
					if ( velocity > 0 ) {
						mAnimatedVelocity = 0;
					}
				} else {
					if ( velocity < 0 ) {
						mAnimatedVelocity = 0;
					}
				}
			} else {
				// We are expanded, but they didn't move sufficiently to cause
				// us to retract. Animate back to the expanded position. so animate BACK to expanded!
				mAnimatedAcceleration = -mMaximumAcceleration;
				
				if( mInvert ) {
					if ( velocity < 0 ) {
						mAnimatedVelocity = 0;
					}
				} else {
					if ( velocity > 0 ) {
						mAnimatedVelocity = 0;
					}
				}
			}
		} else {
			
			// WE'RE COLLAPSED
			
			c1 = mInvert ? velocity < mMaximumMajorVelocity : velocity > mMaximumMajorVelocity;
			c2 = mInvert ? ( position < ( mVertical ? getHeight() : getWidth() ) / 2 ) : ( position > ( mVertical ? getHeight() : getWidth() ) / 2 );
			c3 = mInvert ? velocity < -mMaximumMajorVelocity : velocity > -mMaximumMajorVelocity;
			
			Log.d( LOG_TAG, "COLLAPSED. position: " + position + ", velocity: " + velocity + ", mMaximumMajorVelocity: " + mMaximumMajorVelocity );
			Log.d( LOG_TAG, "COLLAPSED. always: " + always + ", c1: " + c1 + ", c2: " + c2 + ", c3: " + c3 );
			
			if ( !always && ( c1 || ( c2 && c3 ) ) ) {
				mAnimatedAcceleration = mMaximumAcceleration;
				
				if( mInvert ) {
					if ( velocity > 0 ) {
						mAnimatedVelocity = 0;
					}
				} else {
					if ( velocity < 0 ) {
						mAnimatedVelocity = 0;
					}
				}
			} else {
				mAnimatedAcceleration = -mMaximumAcceleration;
				
				if( mInvert ) {
					if ( velocity < 0 ) {
						mAnimatedVelocity = 0;
					}
				} else {
					if ( velocity > 0 ) {
						mAnimatedVelocity = 0;
					}
				}
			}
		}
		
		long now = SystemClock.uptimeMillis();
		mAnimationLastTime = now;
		mCurrentAnimationTime = now + ANIMATION_FRAME_DURATION;
		mAnimating = true;
		mHandler.removeMessages( MSG_ANIMATE );
		mHandler.sendMessageAtTime( mHandler.obtainMessage( MSG_ANIMATE ), mCurrentAnimationTime );
		stopTracking();
	}
	
	private void prepareTracking( int position )
	{
		mTracking = true;
		mVelocityTracker = VelocityTracker.obtain();
		boolean opening = !mExpanded;
		
		if ( opening ) {
			mAnimatedAcceleration = mMaximumAcceleration;
			mAnimatedVelocity = mMaximumMajorVelocity;
			if( mInvert )
				mAnimationPosition = mTopOffset;
			else
				mAnimationPosition = mBottomOffset + ( mVertical ? getHeight() - mHandleHeight : getWidth() - mHandleWidth );
			moveHandle( (int)mAnimationPosition );
			mAnimating = true;
			mHandler.removeMessages( MSG_ANIMATE );
			long now = SystemClock.uptimeMillis();
			mAnimationLastTime = now;
			mCurrentAnimationTime = now + ANIMATION_FRAME_DURATION;
			mAnimating = true;
		} else {
			if ( mAnimating ) {
				mAnimating = false;
				mHandler.removeMessages( MSG_ANIMATE );
			}
			moveHandle( position );
		}
	}
	
	private void moveHandle( int position )
	{
		final View handle = mHandle;
		
		if ( mVertical ) {
			if ( position == EXPANDED_FULL_OPEN ) {
				if( mInvert )
					handle.offsetTopAndBottom( mBottomOffset + getBottom() - getTop() - mHandleHeight );
				else
					handle.offsetTopAndBottom( mTopOffset - handle.getTop() );
				invalidate();
			} else if ( position == COLLAPSED_FULL_CLOSED ) {
				if( mInvert ) {
					handle.offsetTopAndBottom( mTopOffset - handle.getTop() );
				} else {
					handle.offsetTopAndBottom( mBottomOffset + getBottom() - getTop() - mHandleHeight - handle.getTop() );
				}
				invalidate();
			} else 
			{
				final int top = handle.getTop();
				int deltaY = position - top;
				if ( position < mTopOffset ) {
					deltaY = mTopOffset - top;
				} else if ( deltaY > mBottomOffset + getBottom() - getTop() - mHandleHeight - top ) {
					deltaY = mBottomOffset + getBottom() - getTop() - mHandleHeight - top;
				}
				
				handle.offsetTopAndBottom( deltaY );
				
				final Rect frame = mFrame;
				final Rect region = mInvalidate;
				
				handle.getHitRect( frame );
				region.set( frame );
				
				region.union( frame.left, frame.top - deltaY, frame.right, frame.bottom - deltaY );
				region.union( 0, frame.bottom - deltaY, getWidth(), frame.bottom - deltaY + mContent.getHeight() );
				
				invalidate( region );
			}
		} else {
			if ( position == EXPANDED_FULL_OPEN ) {
				if( mInvert )
					handle.offsetLeftAndRight( mBottomOffset + getRight() - getLeft() - mHandleWidth );
				else
					handle.offsetLeftAndRight( mTopOffset - handle.getLeft() );
				invalidate();
			} else if ( position == COLLAPSED_FULL_CLOSED ) {
				if( mInvert )
					handle.offsetLeftAndRight( mTopOffset - handle.getLeft() );
				else
					handle.offsetLeftAndRight( mBottomOffset + getRight() - getLeft() - mHandleWidth - handle.getLeft() );
				invalidate();
			} else {
				final int left = handle.getLeft();
				int deltaX = position - left;
				if ( position < mTopOffset ) {
					deltaX = mTopOffset - left;
				} else if ( deltaX > mBottomOffset + getRight() - getLeft() - mHandleWidth - left ) {
					deltaX = mBottomOffset + getRight() - getLeft() - mHandleWidth - left;
				}
				handle.offsetLeftAndRight( deltaX );
				
				final Rect frame = mFrame;
				final Rect region = mInvalidate;
				
				handle.getHitRect( frame );
				region.set( frame );
				
				region.union( frame.left - deltaX, frame.top, frame.right - deltaX, frame.bottom );
				region.union( frame.right - deltaX, 0, frame.right - deltaX + mContent.getWidth(), getHeight() );
				
				invalidate( region );
			}
		}
	}
	
	private void prepareContent()
	{
		if ( mAnimating ) { return; }
		
		// Something changed in the content, we need to honor the layout request
		// before creating the cached bitmap
		final View content = mContent;
		if ( content.isLayoutRequested() ) {
			
			if ( mVertical ) {
				final int handleHeight = mHandleHeight;
				int height = getBottom() - getTop() - handleHeight - mTopOffset;
				content.measure( MeasureSpec.makeMeasureSpec( getRight() - getLeft(), MeasureSpec.EXACTLY ), MeasureSpec.makeMeasureSpec( height, MeasureSpec.EXACTLY ) );
				
				Log.d( LOG_TAG, "content.layout(2)" );
				
				if ( mInvert ) 
					content.layout( 0, mTopOffset, content.getMeasuredWidth(), mTopOffset + content.getMeasuredHeight() );
				else 
					content.layout( 0, mTopOffset + handleHeight, content.getMeasuredWidth(), mTopOffset + handleHeight + content.getMeasuredHeight() );
			
			} else {
				
				final int handleWidth = mHandle.getWidth();
				int width = getRight() - getLeft() - handleWidth - mTopOffset;
				content.measure( MeasureSpec.makeMeasureSpec( width, MeasureSpec.EXACTLY ), MeasureSpec.makeMeasureSpec( getBottom() - getTop(), MeasureSpec.EXACTLY ) );
				
				if( mInvert )
					content.layout( mTopOffset, 0, mTopOffset + content.getMeasuredWidth(), content.getMeasuredHeight() );
				else
					content.layout( handleWidth + mTopOffset, 0, mTopOffset + handleWidth + content.getMeasuredWidth(), content.getMeasuredHeight() );
			}
		}
		// Try only once... we should really loop but it's not a big deal
		// if the draw was cancelled, it will only be temporary anyway
		content.getViewTreeObserver().dispatchOnPreDraw();
		content.buildDrawingCache();
		
		content.setVisibility( View.GONE );
	}
	
	private void stopTracking()
	{
		mHandle.setPressed( false );
		mTracking = false;
		
		if ( mOnDrawerScrollListener != null ) {
			mOnDrawerScrollListener.onScrollEnded();
		}
		
		if ( mVelocityTracker != null ) {
			mVelocityTracker.recycle();
			mVelocityTracker = null;
		}
	}
	
	private void doAnimation()
	{
		if ( mAnimating ) {
			incrementAnimation();
			
			if( mInvert )
			{
				if ( mAnimationPosition < mTopOffset ) {
					mAnimating = false;
					closeDrawer();
				} else if ( mAnimationPosition >= mTopOffset + ( mVertical ? getHeight() : getWidth() ) - 1 ) {
					mAnimating = false;
					openDrawer();
				} else {
					moveHandle( (int)mAnimationPosition );
					mCurrentAnimationTime += ANIMATION_FRAME_DURATION;
					mHandler.sendMessageAtTime( mHandler.obtainMessage( MSG_ANIMATE ), mCurrentAnimationTime );
				}				
			} else {
				if ( mAnimationPosition >= mBottomOffset + ( mVertical ? getHeight() : getWidth() ) - 1 ) {
					mAnimating = false;
					closeDrawer();
				} else if ( mAnimationPosition < mTopOffset ) {
					mAnimating = false;
					openDrawer();
				} else {
					moveHandle( (int)mAnimationPosition );
					mCurrentAnimationTime += ANIMATION_FRAME_DURATION;
					mHandler.sendMessageAtTime( mHandler.obtainMessage( MSG_ANIMATE ), mCurrentAnimationTime );
				}
			}
		}
	}
	
	private void incrementAnimation()
	{
		long now = SystemClock.uptimeMillis();
		float t = ( now - mAnimationLastTime ) / 1000.0f; // ms -> s
		final float position = mAnimationPosition;
		final float v = mAnimatedVelocity; // px/s
		final float a = mInvert ? mAnimatedAcceleration : mAnimatedAcceleration; // px/s/s
		mAnimationPosition = position + ( v * t ) + ( 0.5f * a * t * t ); // px
		mAnimatedVelocity = v + ( a * t ); // px/s
		mAnimationLastTime = now; // ms
	}
	
	/**
	 * Toggles the drawer open and close. Takes effect immediately.
	 * 
	 * @see #open()
	 * @see #close()
	 * @see #animateClose()
	 * @see #animateOpen()
	 * @see #animateToggle()
	 */
	public void toggle()
	{
		if ( !mExpanded ) {
			openDrawer();
		} else {
			closeDrawer();
		}
		invalidate();
		requestLayout();
	}
	
	/**
	 * Toggles the drawer open and close with an animation.
	 * 
	 * @see #open()
	 * @see #close()
	 * @see #animateClose()
	 * @see #animateOpen()
	 * @see #toggle()
	 */
	public void animateToggle()
	{
		if ( !mExpanded ) {
			animateOpen();
		} else {
			animateClose();
		}
	}
	
	/**
	 * Opens the drawer immediately.
	 * 
	 * @see #toggle()
	 * @see #close()
	 * @see #animateOpen()
	 */
	public void open()
	{
		openDrawer();
		invalidate();
		requestLayout();
		
		sendAccessibilityEvent( AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED );
	}
	
	/**
	 * Closes the drawer immediately.
	 * 
	 * @see #toggle()
	 * @see #open()
	 * @see #animateClose()
	 */
	public void close()
	{
		closeDrawer();
		invalidate();
		requestLayout();
	}
	
	/**
	 * Closes the drawer with an animation.
	 * 
	 * @see #close()
	 * @see #open()
	 * @see #animateOpen()
	 * @see #animateToggle()
	 * @see #toggle()
	 */
	public void animateClose()
	{
		prepareContent();
		final OnDrawerScrollListener scrollListener = mOnDrawerScrollListener;
		if ( scrollListener != null ) {
			scrollListener.onScrollStarted();
		}
		animateClose( mVertical ? mHandle.getTop() : mHandle.getLeft() );
		
		if ( scrollListener != null ) {
			scrollListener.onScrollEnded();
		}
	}
	
	/**
	 * Opens the drawer with an animation.
	 * 
	 * @see #close()
	 * @see #open()
	 * @see #animateClose()
	 * @see #animateToggle()
	 * @see #toggle()
	 */
	public void animateOpen()
	{
		prepareContent();
		final OnDrawerScrollListener scrollListener = mOnDrawerScrollListener;
		if ( scrollListener != null ) {
			scrollListener.onScrollStarted();
		}
		animateOpen( mVertical ? mHandle.getTop() : mHandle.getLeft() );
		
		sendAccessibilityEvent( AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED );
		
		if ( scrollListener != null ) {
			scrollListener.onScrollEnded();
		}
	}
	
	private void closeDrawer()
	{
		moveHandle( COLLAPSED_FULL_CLOSED );
		mContent.setVisibility( View.GONE );
		mContent.destroyDrawingCache();
		
		if ( !mExpanded ) { return; }
		
		mExpanded = false;
		if ( mOnDrawerCloseListener != null ) {
			mOnDrawerCloseListener.onDrawerClosed();
		}
	}
	
	private void openDrawer()
	{
		moveHandle( EXPANDED_FULL_OPEN );
		mContent.setVisibility( View.VISIBLE );
		
		if ( mExpanded ) { return; }
		
		mExpanded = true;
		
		if ( mOnDrawerOpenListener != null ) {
			mOnDrawerOpenListener.onDrawerOpened();
		}
	}
	
	/**
	 * Sets the listener that receives a notification when the drawer becomes
	 * open.
	 * 
	 * @param onDrawerOpenListener
	 *           The listener to be notified when the drawer is opened.
	 */
	public void setOnDrawerOpenListener( OnDrawerOpenListener onDrawerOpenListener )
	{
		mOnDrawerOpenListener = onDrawerOpenListener;
	}
	
	/**
	 * Sets the listener that receives a notification when the drawer becomes
	 * close.
	 * 
	 * @param onDrawerCloseListener
	 *           The listener to be notified when the drawer is closed.
	 */
	public void setOnDrawerCloseListener( OnDrawerCloseListener onDrawerCloseListener )
	{
		mOnDrawerCloseListener = onDrawerCloseListener;
	}
	
	/**
	 * Sets the listener that receives a notification when the drawer starts or
	 * ends a scroll. A fling is considered as a scroll. A fling will also
	 * trigger a drawer opened or drawer closed event.
	 * 
	 * @param onDrawerScrollListener
	 *           The listener to be notified when scrolling starts or stops.
	 */
	public void setOnDrawerScrollListener( OnDrawerScrollListener onDrawerScrollListener )
	{
		mOnDrawerScrollListener = onDrawerScrollListener;
	}
	
	/**
	 * Returns the handle of the drawer.
	 * 
	 * @return The View reprenseting the handle of the drawer, identified by the
	 *         "handle" id in XML.
	 */
	public View getHandle()
	{
		return mHandle;
	}
	
	/**
	 * Returns the content of the drawer.
	 * 
	 * @return The View reprenseting the content of the drawer, identified by the
	 *         "content" id in XML.
	 */
	public View getContent()
	{
		return mContent;
	}
	
	/**
	 * Unlocks the SlidingDrawer so that touch events are processed.
	 * 
	 * @see #lock()
	 */
	public void unlock()
	{
		mLocked = false;
	}
	
	/**
	 * Locks the SlidingDrawer so that touch events are ignores.
	 * 
	 * @see #unlock()
	 */
	public void lock()
	{
		mLocked = true;
	}
	
	/**
	 * Indicates whether the drawer is currently fully opened.
	 * 
	 * @return True if the drawer is opened, false otherwise.
	 */
	public boolean isOpened()
	{
		return mExpanded;
	}
	
	/**
	 * Indicates whether the drawer is scrolling or flinging.
	 * 
	 * @return True if the drawer is scroller or flinging, false otherwise.
	 */
	public boolean isMoving()
	{
		return mTracking || mAnimating;
	}
	
	private class DrawerToggler implements OnClickListener {
		
		public void onClick( View v )
		{
			if ( mLocked ) { return; }
			// mAllowSingleTap isn't relevant here; you're *always*
			// allowed to open/close the drawer by clicking with the
			// trackball.
			
			if ( mAnimateOnClick ) {
				animateToggle();
			} else {
				toggle();
			}
		}
	}
	
	private class SlidingHandler extends Handler {
		
		public void handleMessage( Message m )
		{
			switch ( m.what ) {
				case MSG_ANIMATE:
					doAnimation();
					break;
			}
		}
	}
}



package it.sephiroth.demo.slider;

import it.sephiroth.demo.slider.widget.MultiDirectionSlidingDrawer;
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.Window;
import android.widget.Button;

public class MainActivity extends Activity {

	Button mCloseButton;
	Button mOpenButton;
	MultiDirectionSlidingDrawer mDrawer;
	
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        requestWindowFeature( Window.FEATURE_NO_TITLE );
        setContentView(R.layout.main);
        
        mCloseButton.setOnClickListener( new OnClickListener() {
			@Override
			public void onClick( View v )
			{
				mDrawer.animateClose();
			}
		});
        
        mOpenButton.setOnClickListener( new OnClickListener() {
			
			@Override
			public void onClick( View v )
			{
				if( !mDrawer.isOpened() )
					mDrawer.animateOpen();
			}
		});
    }
    
    @Override
   public void onContentChanged()
   {
   	super.onContentChanged();
   	mCloseButton = (Button) findViewById( R.id.button_close );
   	mOpenButton = (Button) findViewById( R.id.button_open );
   	mDrawer = (MultiDirectionSlidingDrawer) findViewById( R.id.drawer );
   }
}


<?xml version="1.0" encoding="UTF-8"?>
<RelativeLayout android:layout_height="fill_parent" android:layout_width="fill_parent" android:orientation="vertical" xmlns:android="http://schemas.android.com/apk/res/android">
<Button android:layout_height="wrap_content" android:layout_width="100dp" android:visibility="gone" android:layout_centerInParent="true" android:text="@string/open" android:id="@+id/button_open"/>
<it.sephiroth.demo.slider.widget.MultiDirectionSlidingDrawer android:layout_height="wrap_content" android:layout_width="fill_parent" android:id="@+id/drawer" my:content="@+id/content" my:handle="@+id/handle" my:direction="topToBottom" xmlns:my="http://schemas.android.com/apk/res/it.sephiroth.demo.slider">
<include android:id="@id/content" layout="@layout/pen_content"/>
<ImageView android:layout_height="40px" android:layout_width="wrap_content" android:id="@id/handle" android:src="/blog_article/@drawable/sliding_drawer_handle_bottom/index.html"/> </it.sephiroth.demo.slider.widget.MultiDirectionSlidingDrawer> 
</RelativeLayout>

    
[2] Wireshark抓包工具-干爬虫必备
    来源: 互联网  发布时间: 2014-02-18
Wireshark抓包工具--做爬虫必备

 

Wireshark抓包分析TCP的建立与断开过程
分类: 常用debug Tool2011-10-11 20:24 397人阅读 评论(0) 收藏 举报
tcp服务器2010

http://www.joysin.net/network/protocol/wireshark-capture-tcp-establishment-and-disconnect.html

 

Wireshark抓包分析TCP的建立与断开过程

一、TCP建立连接

 

说明:在此图中HostA充当客户端角色,HostB充当服务器角色。

TCP是因特网中的传输层协议,使用三次握手协议建立连接。当主动方发出SYN连接请求后,等待对方回答SYN,ACK。这种建立连接的方法可以防止产生错误的连接,TCP使用的流量控制协议是可变大小的滑动窗口协议。

第一次握手:建立连接时,HostA发送SYN包(SEQ=a)到HostB,并进入SYN_SEND状态,等待HostB确认。

第二次握手:HostB收到SYN包后,必须确认HostA的SYN(ACK=a+1),同时自己也送一个SYN包(SEQ=b),即SYN+ACK包,此时HostB进入SYN_RECV状态。

第三次握手:HostA收到HostB的SYN+ACK包,向HostB发送确认包ACK(ACK=b+1),此包发送完毕,HostA和HostB进入入Established状态,完成三次握手。

抓包验证:

第一次握手:

第二次握手:

第三次握手:

二、TCP断开连接

当数据传输完毕后,需要经过四次握手来断开TCP连接,其步骤如下:

  • HostA要终止连接,发送序列号为p的段,FIN置位,同时确认此前收到的段;
  • HostB收到HostA发送的段后,发送ACK段,确认号为p+1,同时关闭连接。
  • 同时HostB发送序列号为q的段,FIN置位,通知连接关闭;
  • HostA收到HostB发送的段后,发送ACK段,确认号为q+1,同时关闭连接。
  • 抓包验证:

    第一次握手:

    第二、三次握手:

    第四次握手:

    实验完毕!!!!!!!!!!!!!

                                                                                               Joysin

                                                                                           2010.11.30

     


        
    [3] 保护模式准备知识-书中boot.asm代码详细注释
        来源: 互联网  发布时间: 2014-02-18
    保护模式预备知识--书中boot.asm代码详细注释

    一、FAT12软盘格式

           软盘格式如图1:

           每个扇区是512字节,512B*2880=1.44MB

                    

                                   图 1 软盘(1.44MB,FAT12)


           1、引导扇区占512字节,开启后加载这里的512个字节代码,不能把操作系统写在里面,因为太小了。


           2、FAT1,FAT2两者都是一样的,各占9个扇区,如下图。之所以从00000200开始是因为引导扇区占了512字节。

              

              


           由簇号寻找在表中的FAT项,由于第0个和第1个FAT项始终不用,所以最小的簇号为2,簇号为2对应的FAT项为FFF,簇号为3对应的FAT项为008,FAT项的值代表的是文件下一个簇号,但如果值大于或等于0xFF8,则表示当前簇已经是本文件的最后一个簇。如果值为0xFF7,表示它是一个坏簇。       

           

           3、根目录区,存放着根目录条目,每个条目占32个字节,如下图:

           

           由每个条目就能知道文件的名字和条目对应的开始簇号。扇区号=簇号-2,根目录区的扇区大小如下图

           

           RootDirSectors=(224*32+512-1)/ 512=14,共224个根目录条目,每个长度是32字节,每个扇区为512字节。


           4、数据区

           其实起始扇区为19+14+簇号-2

           

    二、int 13h中断

            

           对于1.44MB的软盘来讲,总共有两面(磁头号0和1),每面有80个柱面(0-79),每个柱面有18个扇区。软盘的容量的由来:2×80×18×512=1.44MB,扇区号是这样分配的,0柱面,0磁头是第一个扇区,0柱面,1磁头是第二个扇区,1柱面,0磁头是第三个扇区,1柱面,1磁头是第四个扇区。

            


    三、boot.asm代码详解如下:

           根目录读取一个扇区到内存0900h:0100位置,遍历此扇区的16个根目录,看是否有LOADER  BIN,如果没找到,再读取一个扇区到内存0900h:0100位置,循环刚才的动作,直到14个扇区全部查找完毕;如果找到了,那么取该目录的开始簇号,①根据开始簇号取得他在数据区的扇区号然后读入内存0900h:0100处;然后根据开始簇号取得它在FAT1中的扇区号,然后读入内存08FF:0000处,一般读两个扇区;根据偏移计算FAT项的值,如果为FFF则结束,如果为008,转到①继续执行。0900:0000-0900:0100为堆栈区域。内存分配图如下:

                                           

           代码如下:

    ;%define	_BOOT_DEBUG_	; 做 Boot Sector 时一定将此行注释掉!将此行打开后用 nasm Boot.asm -o Boot.com 做成一个.COM文件易于调试
    
    %ifdef	_BOOT_DEBUG_
    	org  0100h			; 调试状态, 做成 .COM 文件, 可调试
    %else
    	org  07c00h			; Boot 状态, Bios 将把 Boot Sector 加载到 0:7C00 处并开始执行
    %endif
    
    ;================================================================================================
    %ifdef	_BOOT_DEBUG_
    BaseOfStack		equ	0100h	; 调试状态下堆栈基地址(栈底, 从这个位置向低地址生长)
    %else
    BaseOfStack		equ	07c00h	; Boot状态下堆栈基地址(栈底, 从这个位置向低地址生长)
    %endif
    ;equ为伪指令,编译时候就变成对应的代码,本身不占用空间
    BaseOfLoader		equ	09000h	; LOADER.BIN 被加载到的位置 ----  段地址
    OffsetOfLoader		equ	0100h	; LOADER.BIN 被加载到的位置 ---- 偏移地址
    
    RootDirSectors		equ	14	; 根目录占用14个扇区 根据BPB_RootEntCnt计算出来的
    SectorNoOfRootDirectory	equ	19	; 根目录的第一个扇区号,每个根目录项占32个字节
    SectorNoOfFAT1		equ	1	; FAT1 的第一个扇区号 = BPB_RsvdSecCnt
    DeltaSectorNo		equ	17	; DeltaSectorNo = BPB_RsvdSecCnt + (BPB_NumFATs * FATSz) - 2
    					; 文件的开始Sector号 = DirEntry中的开始Sector号 + 根目录占用Sector数目 + DeltaSectorNo
    ;================================================================================================
    
    	jmp short LABEL_START		; Start to boot.
    	nop				; 这个 nop 不可少
        ;一个磁道有18个扇区,一个扇区有512字节
    	; 下面是 FAT12 磁盘的头
    	BS_OEMName	DB 'ForrestY'	; OEM String, 必须 8 个字节
    	BPB_BytsPerSec	DW 512		; 每扇区字节数 ;重要
    	BPB_SecPerClus	DB 1		; 每簇多少扇区
    	BPB_RsvdSecCnt	DW 1		; Boot 记录占用多少扇区 ;所以FAT的第一个扇区为1
    	BPB_NumFATs	DB 2		; 共有多少 FAT 表
    	BPB_RootEntCnt	DW 224		; 根目录文件数最大值 ;计算扇区个数时候用到
    	BPB_TotSec16	DW 2880		; 逻辑扇区总数
    	BPB_Media	DB 0xF0		; 媒体描述符
    	BPB_FATSz16	DW 9		; 每FAT扇区数
    	BPB_SecPerTrk	DW 18		; 每磁道扇区数   ;重要
    	BPB_NumHeads	DW 2		; 磁头数(面数) ;由扇区求柱面,磁头,扇区时候用到
    	BPB_HiddSec	DD 0		; 隐藏扇区数
    	BPB_TotSec32	DD 0		; 如果 wTotalSectorCount 是 0 由这个值记录扇区数
    	BS_DrvNum	DB 0		; 中断 13 的驱动器号 ;后来赋值给dl
    	BS_Reserved1	DB 0		; 未使用
    	BS_BootSig	DB 29h		; 扩展引导标记 (29h)
    	BS_VolID	DD 0		; 卷序列号
    	BS_VolLab	DB 'OrangeS0.02'; 卷标, 必须 11 个字节
    	BS_FileSysType	DB 'FAT12   '	; 文件系统类型, 必须 8个字节  
    
    LABEL_START:	
    	mov	ax, cs ;cs=0000h
    	mov	ds, ax
    	mov	es, ax
    	mov	ss, ax
    	mov	sp, BaseOfStack;上面的地方没有代码,可以自由存数据
    
    	; 清屏
    	mov	ax, 0600h		; AH = 6,  AL = 0h
    	mov	bx, 0700h		; 黑底白字(BL = 07h)
    	mov	cx, 0			; 左上角: (0, 0)
    	mov	dx, 0184fh		; 右下角: (80, 50)
    	int	10h			; int 10h
    
    	mov	dh, 0			; "Booting  "
    	call	DispStr			;int 10号暂时不考虑,功能显示字符串,因为有很多种方式
    	
    	xor	ah, ah	; ┓
    	xor	dl, dl	; ┣ 软驱复位
    	int	13h	; ┛
    	
    ; 下面在 A 盘的根目录寻找 LOADER.BIN
    	mov	word [wSectorNo], SectorNoOfRootDirectory ;19
    LABEL_SEARCH_IN_ROOT_DIR_BEGIN:
    	cmp	word [wRootDirSizeForLoop], 0	; ┓ 14
    	jz	LABEL_NO_LOADERBIN		; ┣ 判断根目录区是不是已经读完
    	dec	word [wRootDirSizeForLoop]	; ┛ 如果读完表示没有找到 LOADER.BIN
    	mov	ax, BaseOfLoader ;09000h
    	mov	es, ax			; es <- BaseOfLoader
    	mov	bx, OffsetOfLoader	; 0100h bx <- OffsetOfLoader	于是, es:bx = BaseOfLoader:OffsetOfLoader
    	mov	ax, [wSectorNo]	; ax <- Root Directory 中的某 Sector 号
    	mov	cl, 1
    	call	ReadSector
    
    	mov	si, LoaderFileName	; ds:si -> "LOADER  BIN"
    	mov	di, OffsetOfLoader	; es:di -> BaseOfLoader:0100,,正好指向根目录项的文件名属性
    	cld
    	mov	dx, 10h ;因为一个扇区最多有512/32=16个根目录
    LABEL_SEARCH_FOR_LOADERBIN:
    	cmp	dx, 0										; 循环次数控制,
    	jz	LABEL_GOTO_NEXT_SECTOR_IN_ROOT_DIR	;如果已经读完这个扇区的所有根目录,就跳到下一个扇区。
    	dec	dx											; 就跳到这个扇区的下一个根目录
    	mov	cx, 11 ;因为根目录的DIR_Name有11个字节
    LABEL_CMP_FILENAME:
    	cmp	cx, 0
    	jz	LABEL_FILENAME_FOUND	; 如果比较了 11 个字符都相等, 表示找到
        dec	cx
    	lodsb				; ds:si -> al
    	cmp	al, byte [es:di]
    	jz	LABEL_GO_ON
    	jmp	LABEL_DIFFERENT		; 只要发现不一样的字符就表明本 DirectoryEntry 不是我们要找的 LOADER.BIN
    LABEL_GO_ON:
    	inc	di
    	jmp	LABEL_CMP_FILENAME	;	继续循环
    
    LABEL_DIFFERENT:
    	and	di, 0FFE0h						; di &= E0 为了让它指向本条目开头
    	add	di, 20h							; di += 20h  下一个目录条目 20h=32个字节
    	mov	si, LoaderFileName				
    	jmp	LABEL_SEARCH_FOR_LOADERBIN;    
    
    LABEL_GOTO_NEXT_SECTOR_IN_ROOT_DIR:
    	add	word [wSectorNo], 1
    	jmp	LABEL_SEARCH_IN_ROOT_DIR_BEGIN
    
    LABEL_NO_LOADERBIN:
    	mov	dh, 2			; "No LOADER."
    	call	DispStr			; 显示字符串
    %ifdef	_BOOT_DEBUG_
    	mov	ax, 4c00h		; ┓
    	int	21h			; ┛没有找到 LOADER.BIN, 回到 DOS
    %else
    	jmp	$			; 没有找到 LOADER.BIN, 死循环在这里
    %endif
    
    LABEL_FILENAME_FOUND:			; 找到 LOADER.BIN 后便来到这里继续
    	mov	ax, RootDirSectors
    	and	di, 0FFE0h		; di -> 当前条目的开始
    	add	di, 01Ah		; 取得此条目对应的开始簇号的偏移
    	mov	cx, word [es:di] ;2
    	push	cx			; 保存此 Sector 在 FAT 中的序号
    	add	cx, ax ;2+14
    	add	cx, DeltaSectorNo	; 19+14+簇号-2
    	mov	ax, BaseOfLoader
    	mov	es, ax			; 
    	mov	bx, OffsetOfLoader	; 
    	mov	ax, cx			; ax=34
    
    LABEL_GOON_LOADING_FILE:
    	push	ax			; `.
    	push	bx			;  |
    	mov	ah, 0Eh			;  | 每读一个扇区就在 "Booting  " 后面
    	mov	al, '.'			;  | 打一个点, 形成这样的效果:
    	mov	bl, 0Fh			;  | Booting ......
    	int	10h			;  |
    	pop	bx			;  |
    	pop	ax			; /
    
    	mov	cl, 1 ;扇区号为34,读一个扇区,到09000h:0100h
    	call	ReadSector
    	pop	ax			; 取出此 Sector 在 FAT 中的序号
    	call	GetFATEntry ;或者FAT项的值
    	cmp	ax, 0FFFh
    	jz	LABEL_FILE_LOADED
    	push	ax			; 保存 Sector 在 FAT 中的序号
    	mov	dx, RootDirSectors
    	add	ax, dx ;ax+14
    	add	ax, DeltaSectorNo ;ax+14+17
    	add	bx, [BPB_BytsPerSec];0100h+200h,又读取一个扇区
    	jmp	LABEL_GOON_LOADING_FILE
    LABEL_FILE_LOADED:
    
    	mov	dh, 1			; "Ready."
    	call	DispStr			; 显示字符串
    
    ; *****************************************************************************************************
    	jmp	BaseOfLoader:OffsetOfLoader	; 这一句正式跳转到已加载到内
    						; 存中的 LOADER.BIN 的开始处,
    						; 开始执行 LOADER.BIN 的代码。
    						; Boot Sector 的使命到此结束
    ; *****************************************************************************************************
    
    
    
    ;============================================================================
    ;变量
    ;----------------------------------------
    wRootDirSizeForLoop:	dw	RootDirSectors	; 因为要用到这个存储单元,不是单一的用14这个数字,Root Directory 占用的扇区数, 在循环中会递减至零.
    wSectorNo:		dw	0		; 要读取的扇区号
    bOdd:		db	0		; 奇数还是偶数
    
    ;============================================================================
    ;字符串
    ;----------------------------------------
    LoaderFileName:		db	"LOADER  BIN", 0	; LOADER.BIN 之文件名
    ; 为简化代码, 下面每个字符串的长度均为 MessageLength
    MessageLength		equ	9
    BootMessage:		db	"Booting  "; 9字节, 不够则用空格补齐. 序号 0
    Message1:		db	"Ready.   "; 9字节, 不够则用空格补齐. 序号 1
    Message2:		db	"No LOADER"; 9字节, 不够则用空格补齐. 序号 2
    ;============================================================================
    
    
    ;----------------------------------------
    ; 函数名: DispStr
    ;----------------------------------------
    ; 作用:
    ;	显示一个字符串, 函数开始时 dh 中应该是字符串序号(0-based)
    DispStr:
    	mov	ax, MessageLength
    	mul	dh
    	add	ax, BootMessage
    	mov	bp, ax			; ┓
    	mov	ax, ds			; ┣ ES:BP = 串地址
    	mov	es, ax			; ┛
    	mov	cx, MessageLength	; CX = 串长度
    	mov	ax, 01301h		; AH = 13,  AL = 01h
    	mov	bx, 0007h		; 页号为0(BH = 0) 黑底白字(BL = 07h)
    	mov	dl, 0
    	int	10h			; int 10h
    	ret
    
    
    ;----------------------------------------
    ; 函数名: ReadSector
    ;----------------------------------------
    ; 作用:
    ;	从第 ax 个 Sector 开始, 将 cl 个 Sector 读入 es:bx 中
    ReadSector:
    	; -----------------------------------
    	; 怎样由扇区号求扇区在磁盘中的位置 (扇区号 -> 柱面号, 起始扇区, 磁头号)
    	; -----------------------------------
    	; 设扇区号为 x
    	;                          ┌ 柱面号 = y >> 1
    	;       x           ┌ 商 y ┤
    	; -------------- => ┤      └ 磁头号 = y & 1
    	;  每磁道扇区数     │
    	;                   └ 余 z => 起始扇区号 = z + 1
    	push	bp ;因为要用到bp
    	mov	bp, sp ;
    	sub	esp, 2			; 辟出两个字节的堆栈区域保存要读的扇区数: byte [bp-2]
    
    	mov	byte [bp-2], cl ;大家奇怪为什么不直接push呢,因为如果直接push,那么则不能直接取出来数据
    	push	bx			; 保存 bx,因为要做除数
    	mov	bl, [BPB_SecPerTrk]	; bl: 除数为18
    	div	bl			; y 在 al 中, z 在 ah 中
    	inc	ah			; z ++
    	mov	cl, ah			; cl <- 起始扇区号
    	mov	dh, al			; dh <- y
    	shr	al, 1			; y >> 1 (其实是 y/BPB_NumHeads, 这里BPB_NumHeads=2)
    	mov	ch, al			; ch <- 柱面号
    	and	dh, 1			; dh & 1 = 磁头号
    	pop	bx			; 恢复 bx
    	; 至此, "柱面号, 起始扇区, 磁头号" 全部得到 ^^^^^^^^^^^^^^^^^^^^^^^^
    	mov	dl, [BS_DrvNum]		; 驱动器号 (0 表示 A 盘)
    .GoOnReading:
    	mov	ah, 2			; 读
    	mov	al, byte [bp-2]		; 读 al 个扇区
    	int	13h
    	jc	.GoOnReading		; 如果读取错误 CF 会被置为 1, 这时就不停地读, 直到正确为止
    
    	add	esp, 2 ;由于前面辟出了两个字节,保存要读的扇区数
    	pop	bp
    
    	ret
    
    ;----------------------------------------
    ; 函数名: GetFATEntry
    ;----------------------------------------
    ; 作用:
    ;	找到序号为 ax 的 Sector 在 FAT 中的条目, 结果放在 ax 中
    ;	需要注意的是, 中间需要读 FAT 的扇区到 es:bx 处, 所以函数一开始保存了 es 和 bx
    GetFATEntry:
    	push	es
    	push	bx
    	push	ax
    	mov	ax, BaseOfLoader; `.
    	sub	ax, 0100h	;  | 在 BaseOfLoader 后面留出 4K 空间用于存放 FAT;9000-0100=8F00,90000和8F000之前差4K
    	mov	es, ax		; /
    	pop	ax ;ax=2
    	mov	byte [bOdd], 0
    	mov	bx, 3
    	mul	bx			; ax=6;
    	mov	bx, 2
    	div	bx			;ax=3(商);dx=0(余数),本质是ax*1.5,为了求偏移
    	cmp	dx, 0
    	jz	LABEL_EVEN
    	mov	byte [bOdd], 1 ;如果为1,说明是奇数
    LABEL_EVEN:;偶数
    	; 现在 ax 中是 FATEntry 在 FAT 中的偏移量,下面来
    	; 计算 FATEntry 在哪个扇区中(FAT占用不止一个扇区)
    	xor	dx, dx			
    	mov	bx, [BPB_BytsPerSec] :512
    	div	bx ; dx:ax / BPB_BytsPerSec
    		   ;  ax <- 商 (FATEntry 所在的扇区相对于 FAT 的扇区号) 结果是0号扇区
    		   ;  dx <- 余数 (FATEntry 在扇区内的偏移) 结果是3号偏移
    	push	dx
    	mov	bx, 0 ; bx <- 0 于是, es:bx = (BaseOfLoader - 100):00
    	add	ax, SectorNoOfFAT1 ; 引导扇区占一个扇区,此句之后的 ax 就是 FATEntry 所在的扇区号
    	mov	cl, 2
    	call	ReadSector ; 读取 FATEntry 所在的扇区, 一次读两个, 避免在边界
    			   ; 发生错误, 因为一个 FATEntry 可能跨越两个扇区
    	pop	dx
    	add	bx, dx ;偏移为3
    	mov	ax, [es:bx] ; 如前面的图所说,ax=8FFFh
    	cmp	byte [bOdd], 1
    	jnz	LABEL_EVEN_2
    	shr	ax, 4   ;如果偏移为4,上步得到ax=008Fh,右移后ax=0008h,与后还为0008h
    LABEL_EVEN_2:
    	and	ax, 0FFFh ;不等于跳到此处,ax=0FFFh
    
    LABEL_GET_FAT_ENRY_OK:
    
    	pop	bx
    	pop	es
    	ret
    ;----------------------------------------
    
    times 	510-($-$$)	db	0	; 填充剩下的空间,使生成的二进制代码恰好为512字节
    dw 	0xaa55				; 结束标志
    




      


        
    最新技术文章:
    ▪Android开发之登录验证实例教程
    ▪Android开发之注册登录方法示例
    ▪Android获取手机SIM卡运营商信息的方法
    ▪Android实现将已发送的短信写入短信数据库的...
    ▪Android发送短信功能代码
    ▪Android根据电话号码获得联系人头像实例代码
    ▪Android中GPS定位的用法实例
    论坛 iis7站长之家
    ▪Android实现文件的分割和组装
    ▪Android录音应用实例教程
    ▪Android双击返回键退出程序的实现方法
    ▪Android实现侦听电池状态显示、电量及充电动...
    ▪Android获取当前已连接的wifi信号强度的方法
    ▪Android实现动态显示或隐藏密码输入框的内容
    ▪根据USER-AGENT判断手机类型并跳转到相应的app...
    ▪Android Touch事件分发过程详解
    ▪Android中实现为TextView添加多个可点击的文本
    ▪Android程序设计之AIDL实例详解
    ▪Android显式启动与隐式启动Activity的区别介绍
    ▪Android按钮单击事件的四种常用写法总结
    ▪Android消息处理机制Looper和Handler详解
    ▪Android实现Back功能代码片段总结
    ▪Android实用的代码片段 常用代码总结
    ▪Android实现弹出键盘的方法
    ▪Android中通过view方式获取当前Activity的屏幕截...
    ▪Android提高之自定义Menu(TabMenu)实现方法
    ▪Android提高之多方向抽屉实现方法
    ▪Android提高之MediaPlayer播放网络音频的实现方法...
    ▪Android提高之MediaPlayer播放网络视频的实现方法...
    ▪Android提高之手游转电视游戏的模拟操控
     


    站内导航:


    特别声明:169IT网站部分信息来自互联网,如果侵犯您的权利,请及时告知,本站将立即删除!

    ©2012-2021,,E-mail:www_#163.com(请将#改为@)

    浙ICP备11055608号-3