• 复制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画面显示内存使用率的浮窗.
     *  当然这里仅仅是简单地仿O(∩_∩)O
     *  
     *  思路整理:
     *  1 涉及到大小两个浮窗.而且两个浮窗之间有逻辑联系.比方:
     *    显示小浮窗时不显示大浮窗.所以利用DriftingWindowManager
     *    来管理这两个浮窗
     *  2 各用一个类来封装和实现两个浮窗的操作
     *  3 以上两个类均继承自Layout
     *  
     *  总的来讲该演示样例还是比較简单的
     *  
     *  学习资料:
     *  1 http://blog.csdn.net/guolin_blog/article/details/8689140
     *  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();
    			}
    		});
    	}
    
    	
    
    }
    

    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.view.LayoutInflater;
    import android.view.MotionEvent;
    import android.view.View;
    import android.view.WindowManager;
    import android.widget.LinearLayout;
    import android.widget.TextView;
    /**
     *小浮窗
     *
     *小浮窗继承自LinearLayout
     *该小浮窗主要实现的功能:
     *1 显示手机的内存使用率
     *2 在Home界面被任意移动位置
     *  所以重点是实现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 width=0;
    	public static int height=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 WindowManager mWindowManager;
    	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);
    		View smallWindowView=layoutInflater.inflate(R.layout.drifting_window_small, this);
    		View driftingSmallWindowRootView=smallWindowView.findViewById(R.id.driftingSmallWindowRootView);
    		TextView percentTextView=(TextView) smallWindowView.findViewById(R.id.percentTextView);
    		//获取小浮窗整个布局的宽和高
    		width=driftingSmallWindowRootView.getLayoutParams().width;
    		height=driftingSmallWindowRootView.getLayoutParams().height;
    		percentTextView.setText(Utils.getAvailMemoryPercent(context));
    		
    		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:
    	            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;
    		         
    	             updateWindowManagerLayoutParams();
    	             
    				break;
    			case MotionEvent.ACTION_UP:
    				 XInScreen_Up=event.getRawX();  
    		         YInScreen_Up=event.getRawY()-statusBarHeight;
    		         if (XInScreen_Down==XInScreen_Up&&YInScreen_Down==YInScreen_Up) {
    		        	 showDriftingBigWindow();
    				}
    				break;
    
    			default:
    				break;
    			}
    
    			return true;
    		}
    		
    	};
    	
    	
    	
    	/**
    	 * 保存小浮窗在Window中的布局參数
    	 */
    	public static void saveWindowManagerLayoutParams(WindowManager.LayoutParams layoutParams){
    		mWindowManagerLayoutParams=layoutParams;
    	}
    	
    	
    	
    	/**
    	 * 更新小浮窗在Window中的布局參数
    	 * 
    	 * 注意事项:
         * 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);
    	}
    	
    	/**
    	 * 显示大浮窗且关闭小浮窗
    	 */
    	private void showDriftingBigWindow(){
    		DriftingWindowManager.showDriftingBiglWindow(mContext);
    		DriftingWindowManager.removeDriftingSmallWindow(mContext);
    	}
    
    }
    

    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;
    	
    	/**
    	 * 显示小浮窗
    	 * 显示位置为屏幕中间右对齐
    	 */
    	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.width;
    			mDriftingSmallWindowLayoutParams.height = DriftingSmallWindow.height;
    			//使小浮窗在屏幕上垂直居中,水平靠右的位置显示
    			mDriftingSmallWindowLayoutParams.x = screenWidth-DriftingSmallWindow.width;
    			mDriftingSmallWindowLayoutParams.y = screenHeight / 2;
    			System.out.println("DriftingSmallWindow.width="+DriftingSmallWindow.width);
    			System.out.println("mDriftingSmallWindowLayoutParams.x="+mDriftingSmallWindowLayoutParams.x);
    			System.out.println("mDriftingSmallWindowLayoutParams.y="+mDriftingSmallWindowLayoutParams.y);
    		}
    		//当显示小浮窗的时保存小浮窗的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;
        	}
        }
        
        
        /**
         * 显示大浮窗
         * 显示位置为屏幕中间
         * 
         * 注意细节问题
         * 例如以下写法,有偏差,显示效果并不好
         * 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);
    					}
    				});
    			}
    		}
    		
    	}
    
    }
    

    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例如以下:

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:id="@+id/driftingBigWindowRootView"
        android:layout_width="130dip"
        android:layout_height="130dip"
        android:orientation="vertical" >
    
        <Button
            android:id="@+id/closeButton"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center_horizontal"
            android:text="关闭全部浮窗" />
    
        <Button
            android:id="@+id/backButton"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center_horizontal"
            android:text="返回到小浮窗" />
    
    </LinearLayout>

    drifting_window_small.xml例如以下:

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout 
        android:id="@+id/driftingSmallWindowRootView"
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="45dip"
        android:layout_height="30dip"
        android:background="#00cc00"
        android:orientation="horizontal" >
    
        <TextView
            android:id="@+id/percentTextView"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:gravity="center"  
            android:textColor="#ff0000"
            android:layout_gravity="center_vertical"
             />
    
    </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>


    版权声明:本文博客原创文章,博客,未经同意,不得转载。

  • 相关阅读:
    Kotlin Coroutines不复杂, 我来帮你理一理
    Refresh design pattern
    Android App安装包瘦身计划
    Google IO 2019 Android 太长不看版
    Effective Java读书笔记完结啦
    探究高级的Kotlin Coroutines知识
    移动应用中的非功能性(跨职能)需求
    Android程序员的Flutter学习笔记
    如何正确使用Espresso来测试你的Android程序
    MVP模式, 开源库mosby的使用及代码分析
  • 原文地址:https://www.cnblogs.com/lcchuguo/p/4721838.html
Copyright © 2020-2023  润新知