Launcher知识的demo,手机管家小伙家与悬浮窗
Launcher知识的demo。主要仿的手机管家小伙家与悬浮窗的效果。东西比較简单。直接贴代码
主要用到了windowManager 中的更新updateViewLayout(view,params),和 加入windowManager.addView()和删除windowManager.removeView()
移动launcher主要是updateViewLayout(view,params),中的params来实现
贴几个主要类,所有源代码请自己下载
package com.pzf.flow; 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; import android.util.Log; /** * 开启服务。用来推断是否是主页面。假设在主页面则显示悬浮窗。否则隐藏悬浮框 * @author pangzf * @time 2014年10月11日 上午11:19:42 */ public class MyService extends Service { private Timer timer; private Handler mHandler = new Handler(); public MyService() { } @Override public IBinder onBind(Intent intent) { return null; } @Override public void onCreate() { super.onCreate(); } @Override public int onStartCommand(Intent intent, int flags, int startId) { // 开启定时器 // 推断是否在主页面,假设在主页面同事small没有显示,则显示small // 开启定时器,每隔0.5秒刷新一次 if (timer == null) { timer = new Timer(); timer.scheduleAtFixedRate(new MyTimerTask(), 0, 500); } return super.onStartCommand(intent, flags, startId); } private class MyTimerTask extends TimerTask { @Override public void run() { showWindow(); } } /** * 推断是否在主页面,假设在主页面同事small没有显示。则显示small */ private void showWindow() { if (MyWindowManager.isHome(getApplicationContext()) && !MyWindowManager.isWindowShowing()) { mHandler.post(new Runnable() { @Override public void run() { MyWindowManager.createSmallWindow(getApplicationContext()); } }); } else if (!MyWindowManager.isHome(getApplicationContext()) && MyWindowManager.isWindowShowing()) { // 假设不是主页,可是已经有窗体了,关掉之前的窗体 mHandler.post(new Runnable() { @Override public void run() { MyWindowManager.removeSmallWindow(getApplicationContext()); } }); } else if (MyWindowManager.isHome(getApplicationContext()) && MyWindowManager.isWindowShowing()) { mHandler.post(new Runnable() { @Override public void run() { MyWindowManager.updatePercent(getApplicationContext()); } }); } } @Override public void onDestroy() { if (timer != null) { timer.cancel(); timer = null; } super.onDestroy(); } }
package com.pzf.flow; import java.io.BufferedReader; import java.io.FileNotFoundException; import java.io.FileReader; import java.util.ArrayList; import java.util.List; import android.app.ActivityManager; import android.app.ActivityManager.MemoryInfo; import android.app.ActivityManager.RunningTaskInfo; import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.graphics.PixelFormat; import android.view.Gravity; import android.view.LayoutInflater; import android.view.View; import android.view.WindowManager; import android.view.WindowManager.LayoutParams; import android.widget.TextView; /** * 管理类。1.用来创建launcher 2.删除launcher 3.更新launcher 4.改变火箭发射台的背景图 5.推断是否主页 6.界面是否存在悬浮框 7。获得执行内存等 * @author pangzf * @time 2014年10月11日 上午11:20:37 */ public class MyWindowManager { private static WindowManager mWindowManager; private static LayoutInflater mInflater; private static SmallView smallWindow; private static WindowManager.LayoutParams smallWindowParams; static int screenWidth; static int screenHeight; private static ActivityManager mActivityManager; private static BigView bigView; private static LayoutParams bigWindowParams; private static RocketLauncher mRocketLauncher; private static LayoutParams mRocketWindowParams; public MyWindowManager(Context context) { mWindowManager = (WindowManager) context .getSystemService(Context.WINDOW_SERVICE); mInflater = (LayoutInflater) context .getSystemService(Context.LAYOUT_INFLATER_SERVICE); } /** * 推断是否是主页面 */ public static boolean isHome(Context context) { ActivityManager activityManager = (ActivityManager) context .getSystemService(Context.ACTIVITY_SERVICE); List<RunningTaskInfo> runningTasks = activityManager.getRunningTasks(1); return getHome(context).contains( runningTasks.get(0).topActivity.getPackageName()); } /*** * 获得主页面 * * @return */ private static List<String> getHome(Context context) { PackageManager packageManager = context.getPackageManager(); Intent intent = new Intent(Intent.ACTION_MAIN); intent.addCategory(Intent.CATEGORY_HOME); List<String> names = new ArrayList<String>(); List<ResolveInfo> list = packageManager.queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY); if (list != null) { for (ResolveInfo info : list) { names.add(info.activityInfo.packageName); } } return names; } /** * 是否有窗体在屏幕上显示 * * @return */ public static boolean isWindowShowing() { return smallWindow != null || bigView != null; } public static void removeSmallWindow(Context context) { if (smallWindow != null) { WindowManager windowManager = getWindowManager(context); windowManager.removeView(smallWindow); smallWindow = null; } } /** * 创建小的window */ // public void createSmallWindow() { // mWindowManager=getWindowManager(mContext); // screenWidth = mWindowManager.getDefaultDisplay().getWidth(); // screenHeight = mWindowManager.getDefaultDisplay().getHeight(); // if (smallView == null) { // smallView = new SmallView(mContext); // // // if (mSamllWindowParams == null) { // mSamllWindowParams = new LayoutParams(); // mSamllWindowParams.type = LayoutParams.TYPE_PHONE; // mSamllWindowParams.format = PixelFormat.RGBA_8888; // mSamllWindowParams.flags = LayoutParams.FLAG_NOT_FOCUSABLE // | LayoutParams.FLAG_NOT_TOUCH_MODAL; // mSamllWindowParams.gravity = Gravity.LEFT | Gravity.TOP; // mSamllWindowParams.width = smallView.getWidth(); // mSamllWindowParams.height = smallView.getHeight(); // mSamllWindowParams.x = screenWidth; // mSamllWindowParams.y = screenHeight/2; // } // smallView.setParams(mSamllWindowParams); // mWindowManager.addView(smallView, mSamllWindowParams); // } // // } public static void createSmallWindow(Context context) { WindowManager windowManager = getWindowManager(context); int screenWidth = windowManager.getDefaultDisplay().getWidth(); int screenHeight = windowManager.getDefaultDisplay().getHeight(); if (smallWindow == null) { smallWindow = new SmallView(context); if (smallWindowParams == null) { smallWindowParams = new LayoutParams(); smallWindowParams.type = LayoutParams.TYPE_SYSTEM_ALERT; smallWindowParams.format = PixelFormat.RGBA_8888; smallWindowParams.flags = LayoutParams.FLAG_NOT_TOUCH_MODAL | LayoutParams.FLAG_NOT_FOCUSABLE; smallWindowParams.gravity = Gravity.LEFT | Gravity.TOP; smallWindowParams.width = smallWindow.viewWidth; smallWindowParams.height = smallWindow.viewHeight; smallWindowParams.x = screenWidth; smallWindowParams.y = screenHeight / 2; } smallWindow.setParams(smallWindowParams); windowManager.addView(smallWindow, smallWindowParams); } } private static WindowManager getWindowManager(Context context) { if (mWindowManager == null) { mWindowManager = (WindowManager) context .getSystemService(Context.WINDOW_SERVICE); } return mWindowManager; } /** * 计算已使用内存的百分比 * * @return */ public static String getUserPercent(Context context) { String dir = "/proc/meminfo"; try { // FileReader fr=new FileReader(dir); // BufferedReader br = new BufferedReader(fr, 2048); // String data = br.readLine(); // String subMemoryLine = data.substring(data.indexOf("MemTotal:")); // br.close(); // long totalMemorySize = // Integer.parseInt(subMemoryLine.replaceAll("\\D+", "")); // long avaliableMemory= getAvalibaleMemory(context)/1024; // int // percent=(int)((totalMemorySize-avaliableMemory)/((float)totalMemorySize*100)); // return percent+"%"; FileReader fr = new FileReader(dir); BufferedReader br = new BufferedReader(fr, 2048); String memoryLine = br.readLine(); String subMemoryLine = memoryLine.substring(memoryLine .indexOf("MemTotal:")); br.close(); long totalMemorySize = Integer.parseInt(subMemoryLine.replaceAll( "\\D+", "")); long availableSize = getAvalibaleMemory(context) / 1024; int percent = (int) ((totalMemorySize - availableSize) / (float) totalMemorySize * 100); return percent + "%"; } catch (Exception e) { e.printStackTrace(); } return "悬浮窗"; } /** * 返回可用的内存 * * @param context * @return */ private static long getAvalibaleMemory(Context context) { MemoryInfo memoryInfo = new ActivityManager.MemoryInfo(); getActivityManager(context).getMemoryInfo(memoryInfo); return memoryInfo.availMem; } private static ActivityManager getActivityManager(Context context) { if (mActivityManager == null) { mActivityManager = (ActivityManager) context .getSystemService(Context.ACTIVITY_SERVICE); } return mActivityManager; } public static void updatePercent(Context context) { if (smallWindow != null) { ((TextView) smallWindow.findViewById(R.id.tv_small_percent)) .setText(getUserPercent(context)); } } public static void createBigView(Context context) { WindowManager windowManager = getWindowManager(context); int screenWidth = windowManager.getDefaultDisplay().getWidth(); int screenHeight = windowManager.getDefaultDisplay().getHeight(); if (bigView == null) { bigView = new BigView(context); if (bigWindowParams == null) { bigWindowParams = new LayoutParams(); bigWindowParams.x = screenWidth / 2 - BigView.viewWidth / 2; bigWindowParams.y = screenHeight / 2 - BigView.viewHeight / 2; bigWindowParams.type = LayoutParams.TYPE_PHONE; bigWindowParams.format = PixelFormat.RGBA_8888; bigWindowParams.gravity = Gravity.LEFT | Gravity.TOP; bigWindowParams.width = BigView.viewWidth; bigWindowParams.height = BigView.viewHeight; } windowManager.addView(bigView, bigWindowParams); } } /** * 将大悬浮窗从屏幕上移除。 * * @param context * 必须为应用程序的Context. */ public static void removeBigWindow(Context context) { if (bigView != null) { WindowManager windowManager = getWindowManager(context); windowManager.removeView(bigView); bigView = null; } } // 火箭--------------- /** * 创建小火箭 * * @param context */ // public static void createRocketWindow(Context context) { // WindowManager windowManager = getWindowManager(context); // int screenWidth = windowManager.getDefaultDisplay().getWidth(); // int screenHeight = windowManager.getDefaultDisplay().getHeight(); // if (mRocketLauncher == null) { // mRocketLauncher = new RocketLauncher(context); // if (mRocketWindowParams == null) { // mRocketWindowParams = new LayoutParams(); // mRocketWindowParams.x = screenWidth / 2 - mRocketLauncher.mRocketWith/2; // mRocketWindowParams.y = screenHeight - mRocketLauncher.mRocketHeight; // // mRocketWindowParams.type = LayoutParams.TYPE_PHONE; // mRocketWindowParams.format = PixelFormat.RGBA_8888; // mRocketWindowParams.flags = LayoutParams.FLAG_NOT_TOUCH_MODAL // | LayoutParams.FLAG_NOT_FOCUSABLE; // mRocketWindowParams.gravity = Gravity.LEFT | Gravity.TOP; // mRocketWindowParams.width = mRocketLauncher.mRocketWith; // mRocketWindowParams.height = mRocketLauncher.mRocketHeight; // } // windowManager.addView(mRocketLauncher, mRocketWindowParams); // } // } // /** * 创建一个火箭发射台,位置为屏幕底部。
*/ public static void createRocketWindow(Context context) { WindowManager windowManager = getWindowManager(context); int screenWidth = windowManager.getDefaultDisplay().getWidth(); int screenHeight = windowManager.getDefaultDisplay().getHeight(); if (mRocketLauncher == null) { mRocketLauncher = new RocketLauncher(context); if (mRocketWindowParams == null) { mRocketWindowParams = new LayoutParams(); mRocketWindowParams.x = screenWidth / 2 - RocketLauncher.mRocketWith / 2; mRocketWindowParams.y = screenHeight - RocketLauncher.mRocketHeight; mRocketWindowParams.type = LayoutParams.TYPE_PHONE; mRocketWindowParams.format = PixelFormat.RGBA_8888; mRocketWindowParams.gravity = Gravity.LEFT | Gravity.TOP; mRocketWindowParams.width = RocketLauncher.mRocketWith; mRocketWindowParams.height = RocketLauncher.mRocketHeight; } windowManager.addView(mRocketLauncher, mRocketWindowParams); } } /** * 移除小火箭l * * @param context */ public static void removeRocketWindow(Context context) { WindowManager windowManager = getWindowManager(context); if (mRocketLauncher != null) { windowManager.removeView(mRocketLauncher); mRocketLauncher = null; } } /** * 更新火箭发射台的显示状态。
*/ public static void updateLauncher() { if (mRocketLauncher != null) { mRocketLauncher.updateRocketLaucher(isReadyToLaunch()); } } /** * 推断小火箭是否准备好发射了。
* * @return 当火箭被发到发射台上返回true,否则返回false。 */ public static boolean isReadyToLaunch() { if ((smallWindowParams.x > mRocketWindowParams.x && smallWindowParams.x + smallWindowParams.width < mRocketWindowParams.x + mRocketWindowParams.width) && (smallWindowParams.y + smallWindowParams.height > mRocketWindowParams.y)) { return true; } return false; } }
package com.pzf.flow; import android.content.Context; import android.view.LayoutInflater; import android.view.View; import android.widget.ImageView; import android.widget.LinearLayout; /** * 小火箭的launcer的布局类。此处须要注意mRocketWith。mRocketHeight这两个字段须要public供外界使用,由于在你移动悬浮框的时候须要显示小火箭。这时候须要小火箭的宽和高 * @author pangzf * @time 2014年10月11日 上午11:22:32 */ public class RocketLauncher extends LinearLayout { public static int mRocketWith; public static int mRocketHeight; private ImageView mRocket; public RocketLauncher(Context context) { super(context); LayoutInflater.from(context).inflate(R.layout.launcher, this); mRocket = (ImageView) findViewById(R.id.launcher_img); mRocketWith = mRocket.getLayoutParams().width; mRocketHeight = mRocket.getLayoutParams().height; } /** * 是否是发射状态 * @param isReadyLaunch */ public void updateRocketLaucher(boolean isReadyLaunch){ mRocket.setImageResource(isReadyLaunch?R.drawable.launcher_bg_fire:R.drawable.launcher_bg_hold); } }
package com.pzf.flow; import java.lang.reflect.Field; import android.content.Context; import android.os.AsyncTask; import android.os.SystemClock; import android.util.AttributeSet; 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; /** * 悬浮框类 * 1.显示内存使用情况 * 2.移动悬浮框,位置改变 OnTouch(); * 3.移动小悬浮框,变成小火箭 updateView() updateStatus(); * 4.移动到发射台,小火箭发射 LaunchTask * @author pangzf * @time 2014年10月11日 上午11:23:48 */ public class SmallView extends LinearLayout { private Context mContext; private int statusBarHeight; private float mXInView; private float mYInView; private float mXDownInScreen; private float mYDownInScreen; private float mXInScreen; private float mYInScreen; /** * 小悬浮窗的參数 */ private WindowManager.LayoutParams mParams; public int viewWidth; public int viewHeight; private WindowManager mWindowManager; private LinearLayout view; private boolean isPressed; private ImageView mIvRocket; private int rocketWidth; private int rocketHeight; public SmallView(Context context) { super(context); this.mContext=context; mWindowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); LayoutInflater.from(context).inflate(R.layout.small, this); view = (LinearLayout) findViewById(R.id.ll_small_main); viewWidth = view.getLayoutParams().width; viewHeight = view.getLayoutParams().height; mIvRocket = (ImageView) findViewById(R.id.rocket_img); rocketWidth = mIvRocket.getLayoutParams().width; rocketHeight = mIvRocket.getLayoutParams().height; TextView mTvPercent = (TextView) view .findViewById(R.id.tv_small_percent); mTvPercent.setText(MyWindowManager.getUserPercent(context)); } /** * 将小悬浮窗的參数传入,用于更新小悬浮窗的位置。* * @param params * 小悬浮窗的參数 */ public void setParams(WindowManager.LayoutParams params) { mParams = params; } // 做单击处理和移动small位置 @Override public boolean onTouchEvent(MotionEvent event) { switch (event.getAction()) { case MotionEvent.ACTION_DOWN: isPressed=true; mXInView = event.getX(); mYInView = event.getY(); mXDownInScreen = event.getRawX(); mYDownInScreen = event.getRawY() - getStatusBarHeight(); mXInScreen = event.getRawX(); mYInScreen = event.getRawY()-getStatusBarHeight(); break; case MotionEvent.ACTION_MOVE: //移动small mXInScreen=event.getRawX(); mYInScreen=event.getRawY() - getStatusBarHeight(); updateStatus(); updateView(); break; case MotionEvent.ACTION_UP: isPressed=false; if(MyWindowManager.isReadyToLaunch()){ //发射小火箭 launchRocket(); }else{ updateStatus(); //推断点击事件 if(mXDownInScreen==mXInScreen&&mYDownInScreen==mYInScreen){ //打开big openBigWindow(); } } break; default: break; } return true; } /** * 发射小火箭 */ private void launchRocket() { MyWindowManager.removeRocketWindow(getContext()); new LuanchTask().execute(); } private class LuanchTask extends AsyncTask<Void, Void, Void>{ @Override protected Void doInBackground(Void... params) { while(mParams.y>0){ mParams.y=mParams.y-10; publishProgress(); SystemClock.sleep(8); } return null; } @Override protected void onProgressUpdate(Void... values) { //依据进度更新小火箭的位置,实现发射效果 mWindowManager.updateViewLayout(SmallView.this, mParams); } @Override protected void onPostExecute(Void result) { super.onPostExecute(result); // 火箭升空结束后。回归到悬浮窗状态 updateStatus(); mParams.x = (int) (mXDownInScreen - mXInView); mParams.y = (int) (mYDownInScreen - mYInView); mWindowManager.updateViewLayout(SmallView.this, mParams); } } /** * 更改小火箭的状态 */ private void updateStatus() { //假设是按下的状态,并且小火箭是不存在的,则显示小火箭。隐藏悬浮框 if(isPressed&&mIvRocket.getVisibility()!=View.VISIBLE){ mParams.width=rocketWidth; mParams.height=rocketHeight; mWindowManager.updateViewLayout(this, mParams); view.setVisibility(View.GONE); mIvRocket.setVisibility(View.VISIBLE); MyWindowManager.createRocketWindow(getContext()); }else if(!isPressed){ //显示悬浮框,隐藏小火箭 mParams.width=viewWidth; mParams.height=viewHeight; mWindowManager.updateViewLayout(this, mParams); view.setVisibility(View.VISIBLE); mIvRocket.setVisibility(View.GONE); MyWindowManager.removeRocketWindow(getContext()); } } /** * 打开大悬浮窗。同一时候关闭小悬浮窗。 */ private void openBigWindow() { MyWindowManager.createBigView(getContext()); MyWindowManager.removeSmallWindow(getContext()); } /** * 移动samll在屏幕上的位置 */ private void updateView() { mParams.x=(int) (mXInScreen-mXInView); mParams.y=(int) (mYInScreen-mYInView); mWindowManager.updateViewLayout(this, mParams); MyWindowManager.updateLauncher(); } /** * 获得状态栏的高度 * * @return */ private float getStatusBarHeight() { if (statusBarHeight == 0) { try { Class<?> clazz = Class.forName("com.android.internal.R$dimen"); Object o = clazz.newInstance(); Field field = clazz.getField("status_bar_height"); Integer size = (Integer) field.get(o); statusBarHeight = getResources().getDimensionPixelSize(size); } catch (Exception e) { e.printStackTrace(); } } return statusBarHeight; } }
效果图
源代码地址:点击打开链接
个人项目txtreader:已经公布google play,http://blog.csdn.net/pangzaifei/article/details/52756777
有须要的能够联系