仿360在Launcher画面显示内存使用率的浮窗(改进版)

MainActivity如下:

package cc.cc;

import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
/**
 *  Demo描述:
 *  仿360在Launcher画面显示内存使用率的浮窗.
 *  当拖动浮窗时,浮窗变成一个小火箭,且在屏幕的底端出现一个火箭发射平台
 *  当拖动浮窗至发射平台手指抬起即可发射火箭.
 *
 *  思路整理:
 *  1 涉及到大小两个浮窗和火箭发射平台.并且三者之间有逻辑联系.比如:
 *    显示小浮窗时不显示大浮窗.所以利用DriftingWindowManager
 *    来管理这两个浮窗和平台
 *  2 各用一个类来封装和实现两个浮窗和火箭发射平台的操作
 *  3 以上三个类均继承自Layout
 *
 *
 *  学习资料:
 *  1 http://blog.csdn.net/guolin_blog/article/details/16919859
 *  2 http://blog.csdn.net/feng88724/article/details/6362710
 *  3 http://blog.csdn.net/hudashi/article/details/6901118
 *  4 http://blog.csdn.net/hudashi/article/details/7060882
 *  5 http://blog.csdn.net/hudashi/article/details/7061240
 *    Thank you very much
 *
 */
public class MainActivity extends Activity {
	private Context mContext;
    private Button mStartButton;
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.main);
		init();
	}

	private void init(){
		mContext=this;
		mStartButton=(Button) findViewById(R.id.button);
		mStartButton.setOnClickListener(new OnClickListener() {
			@Override
			public void onClick(View view) {
				Intent intent=new Intent();
				intent.setAction("dws");
				mContext.startService(intent);
				finish();
			}
		});
	}

}

DriftingWindowManager如下:

package cc.cc;

import android.content.Context;
import android.graphics.PixelFormat;
import android.view.Gravity;
import android.view.WindowManager;
import android.view.WindowManager.LayoutParams;
import android.widget.TextView;

/**
 * 管理大小浮动窗口
 * 在该应用中主要包含了大小两个浮动窗口还有火箭发射平台及其对应的操作
 * 比如显示,更新和移除等,所以就写了个DriftingWindowManager
 * 来实施这些操作.
 * 至于大小浮窗各自要做的操作则是在DriftingSmallWindow和DriftingBigWindow
 * 各个类中具体实施的.
 * 这个和平时其他的代码原理是一样的:
 * 比如在一个类A中使用了(类似于此处的浮窗显示,更新,移除)B和C的对象.
 * 但B和C对象的方法是在各自的类中实现的.
 */
public class DriftingWindowManager {
	private static WindowManager mWindowManager=null;
	private static DriftingSmallWindow mDriftingSmallWindow=null;
	private static DriftingBigWindow mDriftingBigWindow=null;
	//注意该LayoutParams属于android.view.WindowManager.LayoutParams
	private static LayoutParams mDriftingSmallWindowLayoutParams;
	private static LayoutParams mDriftingBigWindowLayoutParams;

	private static RocketPlatform mRocketPlatform;
	private static LayoutParams mRocketPlatformLayoutParams;

	/**
	 * 显示小浮窗
	 * 显示位置为屏幕中间右对齐
	 */
	public static void showDriftingSmallWindow(Context context) {
		WindowManager windowManager = getWindowManager(context);
		int screenWidth = windowManager.getDefaultDisplay().getWidth();
		int screenHeight = windowManager.getDefaultDisplay().getHeight();
		//new了一个DriftingSmallWindow对象,在后面会用WindowManager将
		//其添加到屏幕中
		mDriftingSmallWindow = new DriftingSmallWindow(context);
		if (mDriftingSmallWindowLayoutParams == null) {
			mDriftingSmallWindowLayoutParams = new LayoutParams();
			mDriftingSmallWindowLayoutParams.type = LayoutParams.TYPE_PHONE;
			mDriftingSmallWindowLayoutParams.format = PixelFormat.RGBA_8888;
			mDriftingSmallWindowLayoutParams.flags =
			LayoutParams.FLAG_NOT_TOUCH_MODAL| LayoutParams.FLAG_NOT_FOCUSABLE;
			mDriftingSmallWindowLayoutParams.gravity = Gravity.LEFT| Gravity.TOP;
			mDriftingSmallWindowLayoutParams.width = DriftingSmallWindow.driftingSmallWindowWidth;
			mDriftingSmallWindowLayoutParams.height = DriftingSmallWindow.driftingSmallWindowHeight;
			//使小浮窗在屏幕上垂直居中,水平靠右的位置显示
			mDriftingSmallWindowLayoutParams.x = screenWidth-DriftingSmallWindow.driftingSmallWindowWidth;
			mDriftingSmallWindowLayoutParams.y = screenHeight / 2;
		}
		//当显示小浮窗的时保存小浮窗的LayoutParams至该DriftingSmallWindow对象
		//因为每次移动小浮窗的时候需要修改该LayoutParams的参数值X和Y
		mDriftingSmallWindow.saveWindowManagerLayoutParams(mDriftingSmallWindowLayoutParams);
		mWindowManager.addView(mDriftingSmallWindow,mDriftingSmallWindowLayoutParams);
	}

    /**
     * 更新小浮窗
     */
    public static void updateDriftingSmallWindow(Context context){
    	if(mDriftingSmallWindow!=null){
    		TextView percentTextView=(TextView) mDriftingSmallWindow.findViewById(R.id.percentTextView);
    		percentTextView.setText(Utils.getAvailMemoryPercent(context));
    	}
    }

    /**
     * 移除小浮窗
     */
    public static void removeDriftingSmallWindow(Context context){
    	mWindowManager=getWindowManager(context);
    	if(mWindowManager!=null&&mDriftingSmallWindow!=null){
    		mWindowManager.removeView(mDriftingSmallWindow);
    		mDriftingSmallWindow=null;
    	}
    }

    /**
     * 显示火箭发射平台
     */
	public static void showRocketPlatform(Context context) {
		WindowManager windowManager = getWindowManager(context);
		int screenWidth = windowManager.getDefaultDisplay().getWidth();
		int screenHeight = windowManager.getDefaultDisplay().getHeight();
		mRocketPlatform=new RocketPlatform(context);
		if (mRocketPlatformLayoutParams == null) {
			mRocketPlatformLayoutParams = new LayoutParams();
			mRocketPlatformLayoutParams.x = screenWidth / 2- RocketPlatform.rocketPlatformWidth / 2;
			mRocketPlatformLayoutParams.y = screenHeight - RocketPlatform.rocketPlatformHeight;
			mRocketPlatformLayoutParams.type = LayoutParams.TYPE_PHONE;
			mRocketPlatformLayoutParams.format = PixelFormat.RGBA_8888;
			mRocketPlatformLayoutParams.gravity = Gravity.LEFT | Gravity.TOP;
			mRocketPlatformLayoutParams.width = RocketPlatform.rocketPlatformWidth;
			mRocketPlatformLayoutParams.height = RocketPlatform.rocketPlatformHeight;
		}
		windowManager.addView(mRocketPlatform,mRocketPlatformLayoutParams);
	}

	/**
	 * 更新火箭发射平台状态
	 */
	public static void updateRocketPlatformStatus(){
		if(mRocketPlatform!=null){
			mRocketPlatform.setPlatformBackground(isReadyToFire());
		}
	}

	/**
	 * 判断是否发射火箭
	 */
	public static boolean isReadyToFire(){
		boolean isFire=false;
		if((mDriftingSmallWindowLayoutParams.x>mRocketPlatformLayoutParams.x)&&
		  (mDriftingSmallWindowLayoutParams.x+mDriftingSmallWindowLayoutParams.width<=mRocketPlatformLayoutParams.x+mRocketPlatformLayoutParams.width)&&
		  (mDriftingSmallWindowLayoutParams.y+mDriftingSmallWindowLayoutParams.height>=mRocketPlatformLayoutParams.y)){
			isFire=true;
		}
		return isFire;
	}

	/**
	 * 移除火箭发射平台
	 */
    public static void removeRocketPlatform(Context context){
    	mWindowManager=getWindowManager(context);
    	if(mWindowManager!=null&&mRocketPlatform!=null){
    		mWindowManager.removeView(mRocketPlatform);
    		mRocketPlatform=null;
    	}
    }

    /**
     * 显示大浮窗
     * 显示位置为屏幕中间
     *
     * 注意细节问题
     * 如下写法,有偏差,显示效果并不好
     * mDriftingBigWindowLayoutParams.x = screenWidth / 2;
     * mDriftingBigWindowLayoutParams.y = screenHeight / 2;
     * 给人的感觉是大浮窗并没有在屏幕中间位置.
     * 因为这个mDriftingBigWindowLayoutParams.x(y)指的是大浮窗
     * 在屏幕上显示的x(y)的开始坐标值,即从哪个坐标开始摆放大浮窗.
     * 极端地说如果大浮窗就沙子那么大,那么这么做就没有问题,因为大浮窗
     * 本身就没有什么宽和高.
     * 但在实际中我们还要考虑到控件本身(此处的大浮窗)的长和宽,做到
     * 真的居中显示
     * 所以应该这么写:
     * mDriftingBigWindowLayoutParams.x = screenWidth / 2- DriftingBigWindow.width / 2;
     * mDriftingBigWindowLayoutParams.y = screenHeight / 2- DriftingBigWindow.height / 2;
     * 类似的问题在小浮窗的拖动过程中也有
     */
	public static void showDriftingBiglWindow(Context context) {
		WindowManager windowManager = getWindowManager(context);
		int screenWidth = windowManager.getDefaultDisplay().getWidth();
		int screenHeight = windowManager.getDefaultDisplay().getHeight();
		mDriftingBigWindow = new DriftingBigWindow(context);
		if (mDriftingBigWindowLayoutParams == null) {
			mDriftingBigWindowLayoutParams = new LayoutParams();
			mDriftingBigWindowLayoutParams.x = screenWidth / 2- DriftingBigWindow.width / 2;
			mDriftingBigWindowLayoutParams.y = screenHeight / 2- DriftingBigWindow.height / 2;
			mDriftingBigWindowLayoutParams.type = LayoutParams.TYPE_PHONE;
			mDriftingBigWindowLayoutParams.format = PixelFormat.RGBA_8888;
			mDriftingBigWindowLayoutParams.gravity = Gravity.LEFT | Gravity.TOP;
			mDriftingBigWindowLayoutParams.width = DriftingBigWindow.width;
			mDriftingBigWindowLayoutParams.height = DriftingBigWindow.height;
		}
		windowManager.addView(mDriftingBigWindow,mDriftingBigWindowLayoutParams);
	}

	/**
	 * 移除大浮窗
	 */
    public static void removeDriftingBiglWindow(Context context){
    	mWindowManager=getWindowManager(context);
    	if(mWindowManager!=null&&mDriftingBigWindow!=null){
    		mWindowManager.removeView(mDriftingBigWindow);
    		mDriftingBigWindow=null;
    	}
    }

    /**
     * 是否有浮窗在Launcher上显示
     */
    public static boolean isDriftingWindowShowing(){
    	if (mDriftingSmallWindow!=null||mDriftingBigWindow!=null) {
			return true;
		} else {
           return false;
		}
    }

    /**
     * 获取WindowManager
     */
    private static WindowManager getWindowManager(Context context){
    	if (mWindowManager==null) {
			mWindowManager=(WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
		}
    	return mWindowManager;
    }

}

DriftingWindowService如下:

package cc.cc;

import java.util.Timer;
import java.util.TimerTask;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.os.Handler;
import android.os.IBinder;
/**
 * 利用该服务进行定时任务
 *
 */
public class DriftingWindowService extends Service {
    private Timer mTimer;
    private TimerTask mTimerTask;
    private Context mContext;
    private Handler mHandler;
	@Override
	public void onCreate() {
		super.onCreate();
	}

	@Override
	public void onStart(Intent intent, int startId) {
		super.onStart(intent, startId);
		mContext=this;
		mHandler=new Handler();
		mTimer=new Timer();
		mTimerTask=new TimerTaskSubclass();
		//开启定时的任务
		mTimer.schedule(mTimerTask, 100, 500);
	}

	@Override
	public IBinder onBind(Intent arg0) {
		return null;
	}

	@Override
	public void onDestroy() {
		super.onDestroy();
		if (mTimer!=null) {
			mTimer.cancel();
		}
	}

	private class TimerTaskSubclass extends TimerTask{
		@Override
		public void run() {
			//当前是Launcher,则显示小浮窗
			if (Utils.currentIsLauncher(mContext)&&!DriftingWindowManager.isDriftingWindowShowing()) {
				mHandler.post(new Runnable() {
					@Override
					public void run() {
						DriftingWindowManager.showDriftingSmallWindow(mContext);
					}
				});
			}

			//当前不是Launcher且有浮窗显示,则移除浮窗
			if(!Utils.currentIsLauncher(mContext)&&DriftingWindowManager.isDriftingWindowShowing()){
				mHandler.post(new Runnable() {
					@Override
					public void run() {
						DriftingWindowManager.removeDriftingSmallWindow(mContext);
						DriftingWindowManager.removeDriftingBiglWindow(mContext);
					}
				});
			}

			//当前是Launcher,则更新内存使用率
			if(Utils.currentIsLauncher(mContext)){
				mHandler.post(new Runnable() {
					@Override
					public void run() {
						DriftingWindowManager.updateDriftingSmallWindow(mContext);
					}
				});
			}
		}

	}

}

DriftingBigWindow如下:

package cc.cc;

import android.content.Context;
import android.content.Intent;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.Button;
import android.widget.LinearLayout;
/**
 *大浮窗
 *
 *大浮窗继承自LinearLayout
 *该大浮窗主要实现的功能
 *1 关闭大浮窗显示小浮窗
 *2 关闭所有浮窗且停止对于内存使用率的监控
 *
 *注意方法:
 *LayoutInflater.inflate(int resource, ViewGroup root)的第二参数
 *若设置了root,那么会把新生成的View连接到root,该方法的返回为root.
 *否未设置root,则返回的是新生成的View
 */
public class DriftingBigWindow extends LinearLayout {
	//整个大浮窗的宽和高
    public static int width=0;
    public static int height=0;
    private Context mContext;
	public DriftingBigWindow(Context context) {
		super(context);
		mContext=context;
		LayoutInflater layoutInflater=LayoutInflater.from(mContext);
		View bigWindowView=layoutInflater.inflate(R.layout.drifting_window_big, this);
		View driftingBigWindowRootView=bigWindowView.findViewById(R.id.driftingBigWindowRootView);
		//获取大浮窗整个布局的宽和高
		width=driftingBigWindowRootView.getLayoutParams().width;
		height=driftingBigWindowRootView.getLayoutParams().height;
		//停止服务且移除浮窗
		Button closeButton=(Button) bigWindowView.findViewById(R.id.closeButton);
		closeButton.setOnClickListener(new ClickListenerImpl());
		//显示小浮窗
		Button backButton=(Button) bigWindowView.findViewById(R.id.backButton);
		backButton.setOnClickListener(new ClickListenerImpl());
	}

	private class ClickListenerImpl implements OnClickListener{
		@Override
		public void onClick(View view) {
			switch (view.getId()) {
			case R.id.closeButton:
                Intent intent=new Intent();
                intent.setAction("dws");
                mContext.stopService(intent);
                DriftingWindowManager.removeDriftingSmallWindow(mContext);
                DriftingWindowManager.removeDriftingBiglWindow(mContext);
				break;
			case R.id.backButton:
                DriftingWindowManager.showDriftingSmallWindow(mContext);
                DriftingWindowManager.removeDriftingBiglWindow(mContext);
				break;
			default:
				break;
			}

		}

	}

}

DriftingSmallWindow如下:

package cc.cc;

import android.content.Context;
import android.os.AsyncTask;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.WindowManager;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
/**
 *小浮窗
 *
 *小浮窗继承自LinearLayout
 *该小浮窗主要实现的功能:
 *1 显示手机的内存使用率
 *2 在Home界面被随意移动位置
 *  在移动(Move)过程中小浮窗变成小火箭
 *  所以重点是实现TouchListener,在Touch监听中
 *  不断调用mWindowManager.updateViewLayout()
 *  修改小浮窗或者小火箭在屏幕上的LayoutParams
 *
 *注意方法:
 *LayoutInflater.inflate(int resource, ViewGroup root)的第二参数
 *若设置了root,那么会把新生成的View连接到root,该方法的返回为root.
 *否未设置root,则返回的是新生成的View
 */
public class DriftingSmallWindow extends LinearLayout {
	//小浮窗的宽和高
	public static int driftingSmallWindowWidth=0;
	public static int driftingSmallWindowHeight=0;
	private float XInScreen_Down = 0;
	private float YInScreen_Down = 0;
	private float XInScreen_Move = 0;
	private float YInScreen_Move = 0;
	private float XInScreen_Up = 0;
	private float YInScreen_Up = 0;
	private float XInView_Down=0;
	private float YInView_Down=0;
	private Context mContext;
	private View mRootView;
	private View mDriftingSmallWindowView;
	private WindowManager mWindowManager;
	private boolean isPressed=false;
	private ImageView mRocketImageView;
	private int rocketWidth;
	private int rocketHeight;
	private static WindowManager.LayoutParams mWindowManagerLayoutParams;
	public DriftingSmallWindow(Context context) {
		super(context);
		mContext=context;
		mWindowManager=(WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
		LayoutInflater layoutInflater = LayoutInflater.from(context);
		mRootView=layoutInflater.inflate(R.layout.drifting_window_small, this);
		mDriftingSmallWindowView=mRootView.findViewById(R.id.driftingSmallWindowRootView);
		TextView percentTextView=(TextView) mRootView.findViewById(R.id.percentTextView);

		//获取小浮窗布局的宽和高
		driftingSmallWindowWidth=mDriftingSmallWindowView.getLayoutParams().width;
		driftingSmallWindowHeight=mDriftingSmallWindowView.getLayoutParams().height;
		percentTextView.setText(Utils.getAvailMemoryPercent(context));

		//获取火箭的宽和高
		mRocketImageView=(ImageView) findViewById(R.id.rocketImageView);
		rocketWidth=mRocketImageView.getLayoutParams().width;
		rocketHeight=mRocketImageView.getLayoutParams().height;

		this.setOnTouchListener(new TouchListenerImpl());
		//this.setOnClickListener(new ClickListenerImpl());
	}

	/**
	 * 利用该方式监听点击事件不靠谱
	 * 所以在MotionEvent.ACTION_UP中处理点击事件
	 */
	private class ClickListenerImpl implements OnClickListener{
		@Override
		public void onClick(View view) {
		}
	}

	/**
	 * 对于小浮窗Touch事件的监听
	 * 注意在MotionEvent.ACTION_UP中处理点击事件
	 */
	private class TouchListenerImpl implements OnTouchListener {
		@Override
		public boolean onTouch(View view, MotionEvent event) {
			int statusBarHeight = Utils.getStatusBarHeight(mContext);
			switch (event.getAction()) {
			case MotionEvent.ACTION_DOWN:
				isPressed = true;
				XInScreen_Down = event.getRawX();
				YInScreen_Down = event.getRawY() - statusBarHeight;
				XInView_Down = event.getX();
				YInView_Down = event.getY();
				break;
			case MotionEvent.ACTION_MOVE:
				XInScreen_Move = event.getRawX();
				YInScreen_Move = event.getRawY() - statusBarHeight;
				// 显示小火箭
				showRocketOrDriftingSmallWindow();
				// 更新小火箭的显示位置和火箭发射平台的背景图
				updateWindowManagerLayoutParams();

				break;
			case MotionEvent.ACTION_UP:
				isPressed = false;
				XInScreen_Up = event.getRawX();
				YInScreen_Up = event.getRawY() - statusBarHeight;
				//发射火箭
				if (DriftingWindowManager.isReadyToFire()) {
					fireRocket();
			    //显示小浮窗
				} else {
					showRocketOrDriftingSmallWindow();
					if (XInScreen_Down == XInScreen_Up&&YInScreen_Down == YInScreen_Up) {
						showDriftingBigWindow();
					}
				}
				break;

			default:
				break;
			}

			return true;
		}

	};

	/**
	 * 保存小浮窗在Window中的布局参数
	 *
	 * 当我们使用DriftingWindowManager第一次显示小浮窗时需要用一个参数WindowManager.LayoutParams
	 * 来设置小浮窗在屏幕中显示位置等参数.
	 * 因为每次移动小浮窗或者小火箭的时候需要修改该LayoutParams的参数值X和Y.
	 * 所以保存该小浮窗的LayoutParams至该DriftingSmallWindow对象.
	 * 其实在这个小浮窗中包含了两个东西:除了小浮窗还有一个火箭.
	 * 在初始化时隐藏了小火箭,只显示了小浮窗.
	 * 同一时刻只显示其中的一个,并且两者的宽和高不一致.
	 * 所以需要不断修改WindowManager.LayoutParams变量
	 *
	 * 说白了就是保存了一个对象的某个属性值,并且在随后的操作中不断修改该属性值
	 */
	public static void saveWindowManagerLayoutParams(WindowManager.LayoutParams layoutParams){
		mWindowManagerLayoutParams=layoutParams;
	}

	/**
	 * 显示火箭或者小浮窗
	 */
	private void showRocketOrDriftingSmallWindow(){
		if(isPressed&&mRocketImageView.getVisibility()!=View.VISIBLE){
			mWindowManagerLayoutParams.width=rocketWidth;
			mWindowManagerLayoutParams.height=rocketHeight;
			mWindowManager.updateViewLayout(this, mWindowManagerLayoutParams);
			mDriftingSmallWindowView.setVisibility(View.GONE);
			mRocketImageView.setVisibility(View.VISIBLE);
			//显示火箭发射台
			DriftingWindowManager.showRocketPlatform(mContext);
		}

		if(!isPressed){
			mWindowManagerLayoutParams.width=driftingSmallWindowWidth;
			mWindowManagerLayoutParams.height=driftingSmallWindowHeight;
			mWindowManager.updateViewLayout(this, mWindowManagerLayoutParams);
			mDriftingSmallWindowView.setVisibility(View.VISIBLE);
			mRocketImageView.setVisibility(View.GONE);
			//移除火箭发射台
			DriftingWindowManager.removeRocketPlatform(mContext);
		}
	}

	/**
	 * 更新小火箭的显示位置和火箭发射平台的背景图
	 *
	 * 注意事项:
     * X(Y)InScreen_Move表示触摸点离屏幕左上角的距离
     * X(Y)InView_Down表示触摸点离DriftingSmallWindow火箭自身左上角的距离.
     * 两者相减即得DriftingSmallWindow火箭左上角的坐标
	 */
	private void updateWindowManagerLayoutParams(){
		mWindowManagerLayoutParams.x=(int) (XInScreen_Move-XInView_Down);
		mWindowManagerLayoutParams.y=(int) (YInScreen_Move-YInView_Down);
		mWindowManager.updateViewLayout(this, mWindowManagerLayoutParams);
		//更新火箭发射平台的状态
		DriftingWindowManager.updateRocketPlatformStatus();
	}

	/**
	 * 发射小火箭
	 */
	private void fireRocket(){
		//移除火箭发射平台
		DriftingWindowManager.removeRocketPlatform(mContext);
		FireRocketAsyncTask fireRocketAsyncTask=new FireRocketAsyncTask();
		fireRocketAsyncTask.execute();
	}

	/**
	 * 显示大浮窗且关闭小浮窗
	 */
	private void showDriftingBigWindow(){
		DriftingWindowManager.showDriftingBiglWindow(mContext);
		DriftingWindowManager.removeDriftingSmallWindow(mContext);
	}

	/**
	 * 发射火箭的异步任务
	 */
	private class FireRocketAsyncTask extends AsyncTask<Void, Void, Void>{
		@Override
		protected Void doInBackground(Void... arg0) {
			//不断地修改mWindowManagerLayoutParams中的Y值
			while(mWindowManagerLayoutParams.y>0){
				mWindowManagerLayoutParams.y=mWindowManagerLayoutParams.y-10;
				publishProgress();
				try {
					Thread.sleep(7);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
			return null;
		}
		@Override
		protected void onProgressUpdate(Void... values) {
			super.onProgressUpdate(values);
			mWindowManager.updateViewLayout(DriftingSmallWindow.this, mWindowManagerLayoutParams);
		}
		@Override
		protected void onPostExecute(Void result) {
			super.onPostExecute(result);
			//恢复成悬浮窗口
			showRocketOrDriftingSmallWindow();
			//恢复原来的位置
			mWindowManagerLayoutParams.x=(int) (XInScreen_Down-XInView_Down);
			mWindowManagerLayoutParams.y=(int) (YInScreen_Down-YInView_Down);
			mWindowManager.updateViewLayout(DriftingSmallWindow.this, mWindowManagerLayoutParams);
		}
	}

}

RocketPlatform如下:

package cc.cc;

import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.ImageView;
import android.widget.LinearLayout;

public class RocketPlatform extends LinearLayout {
	private static ImageView mPlatformImageView;
	public static int rocketPlatformWidth=0;
	public static int rocketPlatformHeight=0;
	public RocketPlatform(Context context) {
		super(context);
		LayoutInflater layoutInflater=LayoutInflater.from(context);
		View rootView=layoutInflater.inflate(R.layout.rocket_platform, this);
		mPlatformImageView=(ImageView) rootView.findViewById(R.id.imageView);
		rocketPlatformWidth=mPlatformImageView.getLayoutParams().width;
		rocketPlatformHeight=mPlatformImageView.getLayoutParams().height;
	}

	/**
	 * 依据是否发射小火箭而修改发射平台的背景图片
	 */
	public static void setPlatformBackground(boolean isReadyToFire){
		if (isReadyToFire) {
			mPlatformImageView.setImageResource(R.drawable.platform_bg_fire);
		}else{
			mPlatformImageView.setImageResource(R.drawable.platform_bg_normal);
		}
	}

}

Utils如下:

package cc.cc;

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.lang.reflect.Field;
import java.util.List;
import android.app.ActivityManager;
import android.app.ActivityManager.MemoryInfo;
import android.app.ActivityManager.RunningTaskInfo;
import android.content.ComponentName;
import android.content.Context;

public class Utils {
	/**
	 * 获取设备状态栏高度
	 */
	public static int getStatusBarHeight(Context context) {
		int statusBarHeight = 0;
		try {
			Class clazz = Class.forName("com.android.internal.R$dimen");
			Object object = clazz.newInstance();
			Field field = clazz.getField("status_bar_height");
			// 反射出该对象中status_bar_height字段所对应的在R文件的id值
			// 该id值由系统工具自动生成,文档描述如下:
			// The desired resource identifier, as generated by the aapt tool.
			int id = Integer.parseInt(field.get(object).toString());
			// 依据id值获取到状态栏的高度,单位为像素
			statusBarHeight = context.getResources().getDimensionPixelSize(id);
		} catch (Exception e) {
		}
		return statusBarHeight;
	}

	/**
	 * 判断设备当前是否停留在Launcher
	 */
	public static boolean currentIsLauncher(Context context){
		boolean isLauncher=false;
		String topActivityName=getTopActivityName(context);
		if (topActivityName!=null&&topActivityName.startsWith("HomeActivity")) {
			isLauncher=true;
		}
		return isLauncher;
	}

	/**
	 * 获取栈顶Activity名称
	 */
	public static String getTopActivityName(Context context) {
		String topActivityName = null;
		ActivityManager activityManager =
		(ActivityManager)(context.getSystemService(android.content.Context.ACTIVITY_SERVICE));
		List<RunningTaskInfo> runningTaskInfos = activityManager.getRunningTasks(1);
		if (runningTaskInfos != null) {
			ComponentName f = runningTaskInfos.get(0).topActivity;
			String topActivityClassName = f.getClassName();
			String temp[] = topActivityClassName.split("\\.");
			// 栈顶Activity的名称
			topActivityName = temp[temp.length - 1];
		}
		return topActivityName;
	}

	/**
	 * 获取当前内存的可用率
	 */
	public static String getAvailMemoryPercent(Context context){
		String info=null;
		long availMemory=getAvailMemory(context);
		long totalMemory=getTotalMemory();
		float percent=(availMemory*100/totalMemory);
		info=percent+"%";
		return info;
	}

	/**
	 * 获取内存总大小
	 */
	public static long getTotalMemory() {
		// 系统的内存信息文件
		String filePath = "/proc/meminfo";
		String lineString;
		String[] stringArray;
		long totalMemory = 0;
		try {
			FileReader fileReader = new FileReader(filePath);
			BufferedReader bufferedReader = new BufferedReader(fileReader,1024 * 8);
			// 读取meminfo第一行,获取系统总内存大小
			lineString = bufferedReader.readLine();
			// 按照空格拆分
			stringArray = lineString.split("\\s+");
			// 获得系统总内存,单位KB
			totalMemory = Integer.valueOf(stringArray[1]).intValue();
			bufferedReader.close();
		} catch (IOException e) {
		}
		return totalMemory / 1024;
	}

	/**
	 * 获取可用内存大小
	 */
	public static long getAvailMemory(Context context) {
		ActivityManager activityManager =
		(ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
		MemoryInfo memoryInfo = new MemoryInfo();
		activityManager.getMemoryInfo(memoryInfo);
		return memoryInfo.availMem / (1024 * 1024);
	}

}

main.xml如下:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
   >

    <Button
        android:id="@+id/button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="开启浮动窗口"
        android:layout_centerInParent="true"
    />

</RelativeLayout>

drifting_window_big.xml如下:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
   >

    <Button
        android:id="@+id/button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="开启浮动窗口"
        android:layout_centerInParent="true"
    />

</RelativeLayout>

drifting_window_small.xml如下:

<?xml version="1.0" encoding="utf-8"?>
<!-- 当按住浮窗时,浮窗变为小火箭.所以在此采用 FrameLayout效果会好一些-->
<!-- 如果采用LinearLayout那么会在按下点的附近出现火箭,效果欠佳 -->
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:orientation="vertical" >

    <LinearLayout
        android:id="@+id/driftingSmallWindowRootView"
        android:layout_width="65dip"
        android:layout_height="25dip" >
        <TextView
            android:id="@+id/percentTextView"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center_vertical"
            android:gravity="center"
            android:textColor="#ff0000" />
    </LinearLayout>

    <ImageView
        android:id="@+id/rocketImageView"
        android:layout_width="45dip"
        android:layout_height="90dip"
        android:src="@drawable/rocket"
        android:visibility="gone" />

</FrameLayout>

rocket_platform.xml如下:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:orientation="vertical" >

    <ImageView
        android:id="@+id/imageView"
        android:layout_width="200dip"
        android:layout_height="85dip"
        android:src="@drawable/platform_bg_normal"
      />

</LinearLayout>

AndroidManifest.xml如下:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="cc.cc"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="10"
        android:targetSdkVersion="10" />

     <!-- 注意权限 -->
    <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
    <uses-permission android:name="android.permission.GET_TASKS"/>  

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name="cc.cc.MainActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

        <!-- 注册服务 -->
        <service android:name="cc.cc.DriftingWindowService">
            <intent-filter >
                <action android:name="dws"/>
            </intent-filter>
        </service>
    </application>

</manifest>
时间: 2024-10-29 03:57:24

仿360在Launcher画面显示内存使用率的浮窗(改进版)的相关文章

仿360在Launcher画面显示内存使用率的浮窗(基础版)

MainActivity如下: package cc.cc; import android.os.Bundle; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import android.app.Activity; import android.content.Context; import android.content.Intent; /**

android仿360加速球实现内存释放_Android

现在手机上的悬浮窗应用越来越多,对用户来说,最常见的悬浮窗应用就是安全软件的悬浮小控件,拿360卫士来说,当开启悬浮窗时,它是一个小球,小球可以拖动,当点击小球出现大窗体控件,可以进行进一步的操作如:释放手机内存等等.于是借着慕课网的视频,仿着实现了360加速球,增加了点击小球进行释放内存的功能. 由于是手机只有频幕截图:实现后如下图所示:点击开启按钮,出现悬浮窗小球控件上面显示手机的可用内存百分比:当拖动小球时,小球变为Android图标:松开小球,小球依附在频幕两侧:点击小球,手机底部出现大

Android实现仿360桌面悬浮清理内存_Android

今天闲来无事写了一个清内存的小东西,类似360,在桌面上悬浮,点击后清除后台无用程序,清除后台程序是通过调用ActivityManger.killBackgroundProcesses的方式来进行的,这样的方式有个不好的地方,就是重要性级别设置的高的应用杀不掉.关键代码如下所示 ActivityManager mActivityManager = MyManager.getActivityManager(mContext); List<ActivityManager.RunningAppProc

内存使用率多少是正常的

内存使用率是根据系统当前运行了多少进程决定的,没运行一个进程就会多占用一些内存,对于Win7系统来说基本上启动之后不加载任何程序的情况就会占用到500M的内存了,如果是旗舰版并开启了界面效果的情况,加上一起其它的驱动程序占用内存到1G很正常.同时一切其它的开机启动程序占用内存等,我的电脑之前也是2G内存,Win7旗舰版开机启动项很多占用了很多内存. 进程数和占用的物理内存有直接的关系. 如果不想升级内存,可以尝试关闭一些不必要的开机启动进程来减少内存的使用率.使用360工具就可以轻松设置开机启动

计算机内存使用率过高怎么办

什么是内存使用率 内存使用率就是系统和应用程序占用物理内存的百分比.当电脑在待机状态的时候内存就不会增加,但是如果程序开启的越多,内存使用率就会相应的上升,这就是造成内存使用率过高. 计算机内存使用率过高怎么办-"> 当然如果电脑内存使用率过高的话会造成电脑运行速度慢,操作系统变慢的现象,如果出现了这种情形然后我们在去任务管理器上看看内存使用率是否过高了吧. 如果发现内存使用率过高,不要盲目的去操作电脑,先查看到底是什么程序占用了内存使用率.如果发现是一些正常的程序占用的话可以将其进程暂时

仿360静默安装

转载请注明出处:http://blog.csdn.net/guolin_blog/article/details/47803149 之前有很多朋友都问过我,在Android系统中怎样才能实现静默安装呢?所谓的静默安装,就是不用弹出系统的安装界面,在不影响用户任何操作的情况下不知不觉地将程序装好.虽说这种方式看上去不打搅用户,但是却存在着一个问题,因为Android系统会在安装界面当中把程序所声明的权限展示给用户看,用户来评估一下这些权限然后决定是否要安装该程序,但如果使用了静默安装的方式,也就没

Android静默安装实现方案 仿360手机助手秒装和智能安装功能_Android

之前有很多朋友都问过我,在Android系统中怎样才能实现静默安装呢?所谓的静默安装,就是不用弹出系统的安装界面,在不影响用户任何操作的情况下不知不觉地将程序装好.虽说这种方式看上去不打搅用户,但是却存在着一个问题,因为Android系统会在安装界面当中把程序所声明的权限展示给用户看,用户来评估一下这些权限然后决定是否要安装该程序,但如果使用了静默安装的方式,也就没有地方让用户看权限了,相当于用户被动接受了这些权限.在Android官方看来,这显示是一种非常危险的行为,因此静默安装这一行为系统是

Win7内存使用率高如何解决

  1.首先,我们怎么来判断内存使用率过高?根据一些软件的评判标准来看,一个是看CPU使用率.如果CPU使用率大于15%的话,一般这种情况引起的内存使用率上升属于正常情况. 2.然而还有一个问题,CPU的使用率会有瞬间的跳变的问题.我们要以持续一段时间为衡量的标准. 3.所以最好的一个判断内存使用率过高的标准是看看系统的反应.如果明显感觉系统变慢的话,说明内存的问题.如果系统速度各方面一切正常,那么完全不用关心内存或者cpu的使用率了. 4.好了.大家都知道在任务管理器里可以看到全部这些信息了吧

Win7内存使用率高怎么办?

大家帮帮忙吧,我新买的电脑,内存使用率很高!!一开机就有50%,使得电脑使用很卡,现在开了QQ和几个网页,就到80%了,怎么办啊,我的是W764位系统,2G内存,拜托啦--这个只是一部分管理器截图 Windows7系统本身就比原来的XP系统高很多,增加很多系统功能,这些系统功能都是要占用大量的系统内存的,因此使用Windows7系统2GB内存肯定是不够用的了,如果是的Windows7的高级版本,比如旗舰版,这个版本会有更多的功能,单一个aero peek功能就能长期占用内存数十兆的空间,很多系统