安卓小应用分析之一 360安仔 桌面悬浮

来源:互联网 发布:白板安卓软件 编辑:程序博客网 时间:2024/06/04 18:06
这个项目是从网上找的,自己分析了下。<a target=_blank href="http://download.csdn.net/detail/jonemill/8274695">360安仔,点击打开,不行就复制下下载地址</a> <a target=_blank href="http://download.csdn.net/detail/jonemill/8274695">360安仔下载地址点击打开链接</a>package com.malinkang.AssistAnZai;import android.app.Activity;import android.content.Context;import android.content.Intent;import android.content.SharedPreferences;import android.content.SharedPreferences.Editor;import android.os.Bundle;import android.widget.CheckBox;import android.widget.CompoundButton;import android.widget.CompoundButton.OnCheckedChangeListener;//设置界面/** * 1.刚开启应用,就通过activity开启一项服务。再服务里代码注册广播(目的为了在程序结束的时候可以杀死广播),sendBroadcast发送广播事件。       广播事件一直在后台运行,直到如果接受到的是桌面,就创建安仔。这是其一。   2.在开启应用的时候,通过判断cb,如果打对勾,就在移除安仔。      *  * @author Administrator * */public class SettingActivity extends Activity {private SharedPreferences sp;private Editor editor;private Intent intent;private AnZaiApplication application;@Overridepublic void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.main);//得到应用程序上下文application = (AnZaiApplication) getApplicationContext();//得到sharedpreferancesp = getSharedPreferences("config", Context.MODE_PRIVATE);editor = sp.edit();CheckBox cb = (CheckBox) findViewById(R.id.cb);//得到sp中的值,默认为falseboolean displayOnlyOnHome = sp.getBoolean("displayOnlyOnHome", false);//checkbox默认不开启cb.setChecked(displayOnlyOnHome);//如果checkbox选中,就从application中移除view。 2个判断,这是第一个。一开始就判断if (displayOnlyOnHome) {//此时就只在着桌面显示。application.removeView();//此时在桌面和程序中显示。} else {application.createView();}//给cb设置监听时事件cb.setOnCheckedChangeListener(new OnCheckedChangeListener() {public void onCheckedChanged(CompoundButton buttonView,boolean isChecked) {//向通过editor向sp中放入数据editor.putBoolean("displayOnlyOnHome", isChecked);editor.commit();//这是第二个判断if (isChecked) {//桌面显示application.removeView();} else {//桌面和程序中显示。 application.createView();}}});//开启service。显示地开启intent = new Intent(this, FloatingService.class);startService(intent);}}

package com.malinkang.AssistAnZai;import java.util.ArrayList;import java.util.List;import android.app.ActivityManager;import android.app.ActivityManager.RunningTaskInfo;import android.app.Service;import android.content.BroadcastReceiver;import android.content.Context;import android.content.Intent;import android.content.IntentFilter;import android.content.SharedPreferences;import android.content.pm.PackageManager;import android.content.pm.ResolveInfo;import android.os.AsyncTask;import android.os.IBinder;/** * 开启一项服务。发送广播 。如果收到的在window桌面显示的广播,就在桌面显示。 * 刚开启应用就开启一项服务,如果接受的广播是在手机的桌面,就创建一个小安仔。 * 若果接受的广播不在手机桌面,就不创建。 * @author Administrator * */public class FloatingService extends Service {private SharedPreferences sp;private FloatingService service;private InnerReceiver receiver;private AnZaiApplication application;@Overridepublic IBinder onBind(Intent intent) {return null;}@Overridepublic void onCreate() {//super.onCreate();service=this;//实例化广播事件broadcastRecevierreceiver = new InnerReceiver();sp=getSharedPreferences("config", Context.MODE_PRIVATE);   IntentFilter filter = new IntentFilter();   application = (AnZaiApplication) getApplicationContext();//添加动作filter.addAction("com.malinkang.action.IsHome");filter.addAction("com.malinkang.action.NotHome");//注册接受者  通过代码注册广播。也可以通过在配置文件中添加。registerReceiver(receiver, filter);//开启一个子线程发送广播。new AsyncTask<Void, Void, Void>() {  //这个方法在doinbackgroud中调用。private void send(boolean isHome){//在此项服务中发送广播if(isHome) {//仅在桌面显示service.sendBroadcast(new Intent("com.malinkang.action.IsHome"));System.out.println("zhuomian");} else {service .sendBroadcast(new Intent("com.malinkang.action.NotHome"));System.out.println("bushizhuomian");}}@Overrideprotected Void doInBackground(Void... params) {//默认不在桌面boolean oldIsHome = false;//永真循环while(true){boolean isHome=isHome(); //如果在桌面if(oldIsHome != isHome) {send(isHome);oldIsHome = isHome;}try {Thread.sleep(200);} catch (InterruptedException e) {e.printStackTrace();}}}}.execute();}//初始化浮动窗体//广播接受者    //接受到广播事件然后在onreceiver中处理private class InnerReceiver extends BroadcastReceiver{@Overridepublic void onReceive(Context context, Intent intent) {//如果接受到的广播是sp.getBoolean是假,就什么都不做。if(!sp.getBoolean("displayOnlyOnHome", false)){ System.out.println(sp.getBoolean("displayOnlyOnHome", false));return;}String action = intent.getAction();//如果接受到广播是在桌面就创建if("com.malinkang.action.IsHome".equals(action)){//在桌面window创建viewapplication.createView();System.out.println("是桌面");}else if("com.malinkang.action.NotHome".equals(action)) {application.removeView();System.out.println("不是桌面");}}}//判断是否是桌面 如果是桌面的话就代表,所有activity的包名包含着运行中任务栈最顶端的activity的包名public boolean isHome(){//获取所有桌面的Activity的包名List<String> homes=getHomes();//得到活动管理者。    ActivityManager mActivityManager = (ActivityManager)getSystemService(Context.ACTIVITY_SERVICE);      //在getRunningTasks()所返回的Task队列中系统会根据这些Task的活跃度有一个排序,越活跃越是靠前。第一个就是当前活动的Task    List<RunningTaskInfo> rti = mActivityManager.getRunningTasks(Integer.MAX_VALUE);    //其中runningTaskInfos 的 topActivity就是当前Task的活跃Activity    return homes.contains(rti.get(0).topActivity.getPackageName());} //获取所有桌面的Activity的包名private List<String> getHomes() {  //创建一个arraylist集合。    List<String> packages = new ArrayList<String>();      //得到包管理器。    PackageManager packageManager = getPackageManager();    //新建intent 添加action和category    Intent intent = new Intent(Intent.ACTION_MAIN);      intent.addCategory(Intent.CATEGORY_HOME);      //表示list中只能存放ResolveInfo(这是类)类型的对象。  resolveInfo是个集合。    //返回给定条件的所有ResolveInfo对象(本质上是Activity),集合对象     //根据<intent>节点来获取其上一层目录的信息,通常是<activity>、<receiver>、<service>节点信息    List<ResolveInfo> resolveInfo = packageManager.queryIntentActivities(intent,              PackageManager.MATCH_DEFAULT_ONLY);    //(类型 对象:集合)    for(ResolveInfo info : resolveInfo){    //获取对象中的包名放入另外一个list集合中。    packages.add(info.activityInfo.packageName);        }      return packages;  }//在destory方法中反注册。@Overridepublic void onDestroy() {super.onDestroy();unregisterReceiver(receiver);}}
package com.malinkang.AssistAnZai;import java.util.ArrayList;import java.util.List;import android.app.ActivityManager;import android.app.ActivityManager.RecentTaskInfo;import android.app.Application;import android.content.Context;import android.content.Intent;import android.content.SharedPreferences;import android.content.SharedPreferences.Editor;import android.content.pm.ActivityInfo;import android.content.pm.PackageInfo;import android.content.pm.PackageManager;import android.content.pm.PackageManager.NameNotFoundException;import android.content.pm.ResolveInfo;import android.graphics.PixelFormat;import android.graphics.drawable.Drawable;import android.media.AudioManager;import android.os.Vibrator;import android.support.v4.view.PagerAdapter;import android.support.v4.view.ViewPager;import android.view.Gravity;import android.view.LayoutInflater;import android.view.MotionEvent;import android.view.View;import android.view.View.OnClickListener;import android.view.View.OnTouchListener;import android.view.ViewGroup;import android.view.WindowManager;import android.view.WindowManager.LayoutParams;import android.widget.AdapterView;import android.widget.AdapterView.OnItemClickListener;import android.widget.BaseAdapter;import android.widget.GridView;import android.widget.ImageView;import android.widget.LinearLayout;import android.widget.ScrollView;import android.widget.TextView;import android.widget.Toast;//该悬浮窗口是不隶属于Activity界面的,也就是说,他是隶属于启动它的应用程序所在进程//应用程序的上下文public class AnZaiApplication extends Application {private WindowManager wm;private LayoutParams params;private ImageView iv_anzai;private View view;private Editor editor;private SharedPreferences sp;private boolean isRight;private boolean isMove;private boolean anzaiIsDisplay;// 安仔是否显示private MyOnClickListener mOnClickListener;@Overridepublic void onCreate() {initAnZai();super.onCreate();}/** * 初始化安仔窗体 默认的 不管点击与否,都在window桌面显示  。 */private void initAnZai() {sp = getSharedPreferences("config", Context.MODE_PRIVATE);editor = sp.edit();wm = (WindowManager) getSystemService("window");//wm的参数。params = new LayoutParams();//view控件 这个view要挂在wm上。view = View.inflate(this, R.layout.assist_anzai, null);// 为view注册触摸事件view.setOnTouchListener(new MyOnTouchListener());//子控件iv_anzai = (ImageView) view.findViewById(R.id.anzai_icon);// 判断是否在右边 设置 图片显示,默认在右边isRight = sp.getBoolean("isRight", false);if (isRight) {iv_anzai.setImageResource(R.drawable.assist_anzai_right_green);} else {iv_anzai.setImageResource(R.drawable.assist_anzai_left_green);}//布局参数的类型 格式 标示 xy 高度宽度 gravityparams.type = LayoutParams.TYPE_PHONE;params.format = PixelFormat.RGBA_8888;params.flags = LayoutParams.FLAG_NOT_TOUCH_MODAL| LayoutParams.FLAG_NOT_FOCUSABLE;params.x = (int) sp.getFloat("x", 0);params.y = (int) sp.getFloat("y", 0);params.height = WindowManager.LayoutParams.WRAP_CONTENT;params.width = WindowManager.LayoutParams.WRAP_CONTENT;//左上角params.gravity = Gravity.LEFT | Gravity.TOP;mOnClickListener = new MyOnClickListener();}// 显示安仔   再程序app中添加安仔public void createView() {if (anzaiIsDisplay)return;//显示安仔  向wm中添加view,参数为params。wm.addView(view, params);anzaiIsDisplay = true;}// 移除安仔public void removeView() {if (!anzaiIsDisplay)return;wm.removeView(view);anzaiIsDisplay = false;}/** * 安仔触摸监听器 *  * @author malinkang *  */private class MyOnTouchListener implements OnTouchListener {int startx;int starty;public boolean onTouch(View v, MotionEvent event) {//得到屏幕的宽度int screenWidth = getResources().getDisplayMetrics().widthPixels;switch (event.getAction()) {case MotionEvent.ACTION_DOWN:// 获取按下的时候相对于Activity左上角的坐标startx = (int) event.getRawX();starty = (int) event.getRawY();if (isRight) {iv_anzai.setImageResource(R.drawable.assist_anzai_pressed_right_green);} else {iv_anzai.setImageResource(R.drawable.assist_anzai_pressed_left_green);}break;case MotionEvent.ACTION_MOVE:int newx = (int) event.getRawX();int newy = (int) event.getRawY();if (newx > 35 && (screenWidth - newx) > 35) {isMove = true;iv_anzai.setImageResource(R.drawable.assist_anzai_middle_green);int dx = newx - startx;int dy = newy - starty;params.x += dx;params.y += dy;// 更新wm.updateViewLayout(view, params);// 对初始坐标重新赋值startx = (int) event.getRawX();starty = (int) event.getRawY();}break;//手抬起的时候。case MotionEvent.ACTION_UP:if (isMove) {isMove = false;float halfScreen = screenWidth / 2;if (startx <= halfScreen) {//如果在左边的话,手抬起的时候,把x设为0;params.x = 0;wm.updateViewLayout(view, params);iv_anzai.setImageResource(R.drawable.assist_anzai_left_green);//保存为x=0;editor.putFloat("x", 0);isRight = false;} else {params.x = screenWidth;wm.updateViewLayout(view, params);iv_anzai.setImageResource(R.drawable.assist_anzai_right_green);editor.putFloat("x", screenWidth);isRight = true;}editor.putFloat("y", starty);editor.putBoolean("isRight", isRight);editor.commit();} else {//初始化的时候判断。if (isRight) {iv_anzai.setImageResource(R.drawable.assist_anzai_right_green);} else {iv_anzai.setImageResource(R.drawable.assist_anzai_left_green);}if (mOnClickListener != null) {mOnClickListener.onClick(view);}}break;}return true;}}/** * 安仔点击监听器,点击时候,出现悬浮框 点击事件就是在窗体wm中再添加一个view。 *  * @author malinkang *  */private class MyOnClickListener implements OnClickListener {public void onClick(View v) {initFloatWindow();createFloatWindow();}}/** * 初始化设置窗体 */private View floatView;private LayoutParams params2;private WindowManager floatWindow;private void initFloatWindow() {floatWindow = (WindowManager) getSystemService("window");params2 = new LayoutParams();//初始化设置ui。floatView = initFloatUI();params2.type = LayoutParams.TYPE_PHONE;params2.format = PixelFormat.RGBA_8888;params2.flags = LayoutParams.FLAG_NOT_TOUCH_MODAL| LayoutParams.FLAG_NOT_FOCUSABLE;params2.x = 5;params2.y = 25;params2.height = 400;params2.width = 320;params2.gravity = Gravity.LEFT | Gravity.TOP;}private boolean floatWindowIsDisplay;//创造浮动窗体public void createFloatWindow() {if (floatWindowIsDisplay)return;floatWindow.addView(floatView, params2);floatWindowIsDisplay = true;}//移除浮动窗体public void removeFloatWindow() {if (!floatWindowIsDisplay)return;floatWindow.addView(floatView, params2);floatWindowIsDisplay = false;}/** * 初始化浮动窗体界面 *  * @return */private List<View> views;private SwitcherItemView switch_ringtone;private SwitcherItemView switch_vibrate;private List<AppInfo> appInfos;private View initFloatUI() {//View view = View.inflate(getApplicationContext(),R.layout.assist_float_window, null);//得到viewpaper。子控件ViewPager assist_viewpager = (ViewPager) view.findViewById(R.id.assist_viewpager);//new一个集合。views = new ArrayList<View>();//new 一个线性布局pager_1。LinearLayout pager_1 = new LinearLayout(getApplicationContext());pager_1.setOrientation(1);//得到scrollview对象。ScrollView assist_switcher_container = (ScrollView) View.inflate(getApplicationContext(), R.layout.assist_switcher_container,null);//将scrollview加入线性布局中。pager_1.addView(assist_switcher_container);//initFindView(assist_switcher_container);LayoutInflater.from(getApplicationContext()).inflate(R.layout.assist_process_clear, pager_1, true);//向PagerAdapter添加的第一个view。向PagerAdapterviews.add(pager_1);LinearLayout pager_2 = (LinearLayout) View.inflate(getApplicationContext(), R.layout.assist_task_view, null);//向pageradapter添加的第二个。views.add(pager_2);//获取pager2里面的gridview。GridView float_grid = (GridView) pager_2.findViewById(R.id.float_grid);//获取最近的recenttask。appInfos = getRecentTask();// gridview 中的适配器MyAdapter adapter = new MyAdapter();//给gridview设置适配器float_grid.setAdapter(adapter);//gridveiw子项设置监听float_grid.setOnItemClickListener(new OnItemClickListener() {public void onItemClick(AdapterView<?> parent, View view,int position, long id) {Toast.makeText(getApplicationContext(), position + "",Toast.LENGTH_LONG).show();}});MyPagerAdapter adapter2 = new MyPagerAdapter();//给viewpaper设置适配器。2页。assist_viewpager.setAdapter(adapter2);return view;}/** * 查找ScrollView上的控件SwitcherItemView *  * @param view *///查找private void initFindView(ScrollView view) {switch_ringtone = (SwitcherItemView) view.findViewById(R.id.switch_ringtone);switch_vibrate = (SwitcherItemView) view.findViewById(R.id.switch_vibrate);}/** * ViewPager适配器     PagerAdapter *  * @author malinkang *  *///private class MyPagerAdapter extends PagerAdapter {@Overridepublic int getCount() {return 2;}@Overridepublic boolean isViewFromObject(View arg0, Object arg1) {return arg0 == arg1;}@Overridepublic Object instantiateItem(ViewGroup container, int position) {container.addView(views.get(position));return views.get(position);}}/** * 设置 *  * @param v */public void onClick(View v) {//声音管理器AudioManager am = (AudioManager) getApplicationContext().getSystemService(Context.AUDIO_SERVICE);//震动管理器Vibrator vibrator = (Vibrator) getApplicationContext().getSystemService(Context.VIBRATOR_SERVICE);switch (v.getId()) {case R.id.switch_ringtone:// 设置铃声if (switch_ringtone.isSelected()) {am.setRingerMode(AudioManager.RINGER_MODE_SILENT);switch_ringtone.setSelected(false);Toast.makeText(getApplicationContext(), "铃声已关闭", 0).show();} else {am.setRingerMode(AudioManager.RINGER_MODE_NORMAL);switch_ringtone.setSelected(true);Toast.makeText(getApplicationContext(), "铃声已开启", 0).show();}break;case R.id.switch_vibrate:// 设置手机震动if (switch_vibrate.isSelected()) {am.setRingerMode(AudioManager.RINGER_MODE_NORMAL);switch_vibrate.setSelected(false);Toast.makeText(getApplicationContext(), "震动关闭", 0).show();} else {vibrator.vibrate(100);am.setRingerMode(AudioManager.RINGER_MODE_VIBRATE);switch_vibrate.setSelected(true);Toast.makeText(getApplicationContext(), "震动已开启", 0).show();}break;case R.id.switch_gps:// 设置GPSbreak;}}/** * 显示最近任务的GridView适配器    BaseAdapter 显示gridview中的每一项。 *  * @author malinkang *  */private class MyAdapter extends BaseAdapter {public int getCount() {return appInfos.size();}public Object getItem(int position) {return null;}public long getItemId(int position) {return 0;}public View getView(int position, View convertView, ViewGroup parent) {View view;ViewHolder holder;//复用convertview。if (convertView != null && convertView instanceof LinearLayout) {view = convertView;//holder = (ViewHolder) view.getTag();} else {//得到view。view = View.inflate(getApplicationContext(),R.layout.assist_task_item, null);//对象。holder = new ViewHolder();//得到子控件,给子控件赋值。holder.item_label = (TextView) view.findViewById(R.id.item_label);holder.item_icon = (ImageView) view.findViewById(R.id.item_icon);//给view设置tag。可以使用setTag把查找的view缓存起来方便多次重用//View中的setTag(Onbect)表示给View添加一个格外的数据,以后可以用getTag()将这个数据取出来。view.setTag(holder);}AppInfo appInfo = appInfos.get(position);holder.item_icon.setImageDrawable(appInfo.getIco());holder.item_label.setText(appInfo.getAppName());return view;}}static class ViewHolder {TextView item_label;ImageView item_icon;}/** * 用于获取最近应用的信息 *  * @return */public List<AppInfo> getRecentTask() {ActivityManager am = (ActivityManager) getApplicationContext().getSystemService(Context.ACTIVITY_SERVICE);PackageManager pm = getApplicationContext().getPackageManager();//得到最近运行程序的集合List<RecentTaskInfo> recentTaskInfos = am.getRecentTasks(64, 0);List<AppInfo> appInfos = new ArrayList<AppInfo>();AppInfo appInfo = null;for (RecentTaskInfo recentTaskInfo : recentTaskInfos) {appInfo = new AppInfo();//这个intent可以将重新启动任务。将任务带向前台Intent intent = recentTaskInfo.baseIntent;//查询是否有符合条件的activity。ResolveInfo resolveInfo = pm.resolveActivity(intent, 0);if (resolveInfo != null) {//icon name packagename这3个信息构成一个实体。Drawable appico = resolveInfo.loadIcon(pm);appInfo.setIco(appico);String appName = resolveInfo.loadLabel(pm).toString();appInfo.setAppName(appName);String packageName = resolveInfo.activityInfo.packageName;appInfo.setPackageName(packageName);appInfos.add(appInfo);}}return appInfos;}/** * 打开应用    传入包名就可以打开应用 *  * @param packageName */private void startupApk(String packageName) {// 开启这个应用程序的第一个activity.try {//通过包名得到包信息PackageInfo packinfo = getPackageManager().getPackageInfo(packageName, PackageManager.GET_ACTIVITIES);//得到包里面的所有activityActivityInfo[] activityinfos = packinfo.activities;if (activityinfos != null && activityinfos.length > 0) {ActivityInfo activityinfo = activityinfos[0];Intent intent = new Intent();//intent.setClassName(arg1,arg2)中的arg1是被调用程序B的包名,arg2是B程序中目的activity的完整类名。intent.setClassName(activityinfo.packageName, activityinfo.name);startActivity(intent);} else {Toast.makeText(this, "无法开启当前应用", 0).show();}} catch (NameNotFoundException e) {e.printStackTrace();Toast.makeText(this, "无法开启当前应用", 0).show();}}}布局package com.malinkang.AssistAnZai;import android.content.Context;import android.content.res.TypedArray;import android.graphics.drawable.Drawable;import android.util.AttributeSet;import android.view.View;import android.widget.ImageView;import android.widget.RelativeLayout;import android.widget.TextView;//自定义布局public class SwitcherItemView extends  RelativeLayout {    private View view;    private TextView tv_switcher_label;    private ImageView iv_switcher_icon;    private Drawable switcher_icon;    private String switcher_label;    //带defStyle的构造方法。    public SwitcherItemView(Context context, AttributeSet attrs, int defStyle) {        super(context, attrs, defStyle);        initView(context);    }  //带属性集的构造方法    public SwitcherItemView(Context context, AttributeSet attrs) {        super(context, attrs);        //得到控件的子对象。        initView(context);        //获取到TypedArray。传入的参数是values包下attrs.xml文件。        TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.SwitcherItemView);        //获取图片        switcher_icon = ta.getDrawable(R.styleable.SwitcherItemView_switcher_icon);        //获取文本        switcher_label = ta.getString(R.styleable.SwitcherItemView_switcher_label);        //iv设置图片资源        iv_switcher_icon.setImageDrawable(switcher_icon);        //tv设置文本资源        tv_switcher_label.setText(switcher_label);    }    public SwitcherItemView(Context context) {        super(context);        initView(context);    }    public void initView(Context context){        //通过inflate获取view对象。之后获取子对象。        view = View.inflate(context, R.layout.assist_switcher_item, this);        iv_switcher_icon = (ImageView) view.findViewById(R.id.switch_icon);        tv_switcher_label = (TextView) view.findViewById(R.id.switch_label);            }    } 
0 0