本文出处:http://blog.csdn.net/sk719887916/article/details/40348853,作者:skay
     阅读此文建议先阅读 安卓Tv开发(二)移动智能电视之焦点控制(按键事件)      接触TV的的开发,操作体验是我们开发者必须要关注的,因此,遥控器做鼠标成了智能设备的开发主流不可缺少的一部分,今天给大家带来怎样实现遥控操作模拟鼠标的功能,觉得ok的请到下方自觉的点个赞。有自动化测试框架也有用此方式实现的。    实现功能: 遥控器方向键控制鼠标箭头移动                        遥控器可以操作模拟鼠标进行点击操作。   效果图:
    实现之前先做个大致分析,记得之前我在一篇安卓实现高仿Ios桌面的博客中就接触过类似此需求的功能,第一眼大家觉得可拖动gridview和实现遥控器拖动鼠标有啥关系,仔细一分析,其实异曲同工,可拖动的gridView我们是用手指进行item移动的,而这次的模拟鼠标我们可以把它想成一个item(只不过展现的UI为一个鼠标箭头的图片),用遥控器进行控制的,当然我们无需拖动,用遥控方向键来控制item的位移即可。至于遥控器点击OK键进行点击执行点击操作的事件,我们可以获取模拟鼠标在屏幕中的绝对坐标,然后模拟一个此处的点击事件即可。

      一 自定义鼠标视图

        用于展现鼠标的具体视图,MouseView 继承 FrameLayout ,之后漂浮在控制的activity上,只要由WindowManage控制此视图的展现和移动。
public MouseView(Context context) {super(context);}public MouseView(Context context, MouseManager mMouseMrg) {super(context);init( mMouseMrg);}public OnMouseListener getOnMouseListener() {return mOnMouseListener;}public void setOnMouseListener(OnMouseListener mOnMouseListener) {this.mOnMouseListener = mOnMouseListener;}@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {super.onMeasure(widthMeasureSpec, heightMeasureSpec);if (mMouseView != null && mMouseBitmap != null) {mMouseView.measure(MeasureSpec.makeMeasureSpec(mMouseBitmap.getWidth(), MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(mMouseBitmap.getHeight(), MeasureSpec.EXACTLY));}}private void init(MouseManager manager) {mMouseManager  = manager;Drawable drawable =getResources().getDrawable(R.drawable.shubiao);mMouseBitmap = drawableToBitamp(drawable);mMouseView = new ImageView(getContext());mMouseView.setImageBitmap(mMouseBitmap);addView(mMouseView, new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));mOffsetX = (int)((mMouseBitmap.getWidth()));mOffsetY = (int)((mMouseBitmap.getHeight()));}@Overrideprotected void onLayout(boolean changed, int left, int top, int right,int bottom) {if(mMouseView != null) {mMouseView.layout(mMouseX, mMouseY, mMouseX + mMouseView.getMeasuredWidth(), mMouseY + mMouseView.getMeasuredHeight());}}

     二 鼠标控制器

      用来处理点击事件,和鼠标移动事件。主要是重写事件分发方法 dispatchKeyEvent(KeyEvent event),用于控制鼠标移动和点击。    
/** * @param parent * @param type */public void init(ViewGroup parentView, int type) {mParentView = parentView;mContext = parentView.getContext();mMouseView = new MouseView(mContext, this);mMouseView.setOnMouseListener(this);mCurrentType = type;}/** * @return */public boolean getMouseType() {return isMouseType;}/** * @return */public int getCurrentActivityType() {return mCurrentType;}/** * showmouse */public void showMouseView() {ViewGroup.LayoutParams lp = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,ViewGroup.LayoutParams.MATCH_PARENT);if(mMouseView != null) {mParentView.addView(mMouseView, lp);}}public boolean onDpadClicked(KeyEvent event) {if(!isMouseType) {return false;}if(event.getKeyCode() == KEYCODE_CENTER) {dispatchKeyEventToMouse(event);} else {if(event.getAction() == KeyEvent.ACTION_DOWN) {if(!isKeyEventCousumed) {if(event.getDownTime() - mLastEventTime < defTimes) {if(mSpeed < defMaxSpeed) {mSpeed ++;}} else {mSpeed = 1;}}mLastEventTime = event.getDownTime();dispatchKeyEventToMouse(event);isKeyEventCousumed = true;} else if(event.getAction() == KeyEvent.ACTION_UP) {if(!isKeyEventCousumed){dispatchKeyEventToMouse(event);}isKeyEventCousumed = false;}}return true;}public void sendCenterClickEvent(int x, int y, int action) {sendMotionEvent(x, y, action);}@SuppressLint("InlinedApi")public void sendMouseHoverEvent(int downx, int downy) {sendMotionEvent(downx, downy, MotionEvent.ACTION_HOVER_MOVE);}@TargetApi(Build.VERSION_CODES.HONEYCOMB_MR1)@SuppressLint("NewApi")private void sendMotionEvent(int x, int y, int action) {MotionEvent motionEvent = getMotionEvent( x, y ,action) ;if(action == MotionEvent.ACTION_HOVER_MOVE) {motionEvent.setSource(InputDevice.SOURCE_CLASS_POINTER);mMouseView.dispatchGenericMotionEvent(motionEvent);//mParentView.dispatchGenericMotionEvent(motionEvent);} else {//mParentView.dispatchTouchEvent(motionEvent);mMouseView.dispatchTouchEvent(motionEvent);}}private  MotionEvent getMotionEvent(int downx, int downy, int action) {// TODO Auto-generated method stublong downTime = SystemClock.uptimeMillis();long eventTime = SystemClock.uptimeMillis();int metaState = 0;return MotionEvent.obtain(downTime, eventTime, action, downx, downy, metaState);}@Overridepublic boolean onclick(View v, KeyEvent et) {if (getMouseType()) {return onDpadClicked(et);}return mParentView.dispatchKeyEvent(et);}
          

     三 当前页面加入鼠标

         如果某个activity需要加入鼠标,只要初始化 MouseManager,然后设置当先鼠标显示即可,本次为了方便操作和直观的显示,加入一个webView加载网页,用于鼠标控制操作。
public class MainActivity extends Activity {WindowManager wm;WindowManager.LayoutParams params;private MouseManager mMouseManager;public static ViewGroup contentView;private WebView webView;private View mLoginStatusView;private TextView mLoaddingMessageView;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);LayoutInflater inflater = getLayoutInflater();contentView = (ViewGroup) inflater.inflate(R.layout.test, null);setContentView(contentView);init();initMouse();showMouse();}private void init() {webView = (WebView) contentView.findViewById(R.id.web);mLoginStatusView = this.findViewById(R.id.login_status);mLoaddingMessageView = (TextView) this.findViewById(R.id.login_status_message);Button button = (Button) contentView.findViewById(R.id.btn_onclick);button.setOnClickListener(new OnClickListener() {@Overridepublic void onClick(View v) {Toast.makeText(MainActivity.this, "onclicked ", 1).show();showProgress(true);webView.setVisibility(View.VISIBLE);webView.loadUrl("https://www.baidu.com/");WebSettings settings = webView.getSettings();settings.setJavaScriptEnabled(true);webView.setWebViewClient(new WebViewClient() {@Overridepublic boolean shouldOverrideUrlLoading(WebView view,String url) {view.loadUrl(url);return true;}@Overridepublic void onPageFinished(WebView view, String url) {super.onPageFinished(view, url);}@Overridepublic void onReceivedError(WebView view, int errorCode,String description, String failingUrl) {Toast.makeText(MainActivity.this, "加载失败 ",Toast.LENGTH_LONG).show();super.onReceivedError(view, errorCode, description,failingUrl);}});webView.setWebChromeClient(new WebChromeClient() {@Overridepublic void onProgressChanged(WebView view, int newProgress) {// TODO Auto-generated method stubif (newProgress == 100) {showProgress(false);} else {}}});}});}@SuppressLint("NewApi")private void showProgress(final boolean show) {// On Honeycomb MR2 we have the ViewPropertyAnimator APIs, which allow// for very easy animations. If available, use these APIs to fade-in// the progress spinner.if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR2) {int shortAnimTime = getResources().getInteger(android.R.integer.config_shortAnimTime);mLoginStatusView.setVisibility(View.VISIBLE);mLoginStatusView.animate().setDuration(shortAnimTime).alpha(show ? 1 : 0).setListener(new AnimatorListenerAdapter() {@Overridepublic void onAnimationEnd(Animator animation) {webView.setVisibility(show ? View.VISIBLE: View.GONE);}});webView.setVisibility(View.VISIBLE);webView.animate().setDuration(shortAnimTime).alpha(show ? 0 : 1).setListener(new AnimatorListenerAdapter() {@Overridepublic void onAnimationEnd(Animator animation) {webView.setVisibility(show ? View.GONE: View.VISIBLE);}});} else {// The ViewPropertyAnimator APIs are not available, so simply show// and hide the relevant UI components.mLoginStatusView.setVisibility(show ? View.VISIBLE : View.GONE);webView.setVisibility(show ? View.GONE : View.VISIBLE);}}private void showMouse() {mMouseManager.showMouseView();}public void initMouse() {initMouseMrg();}public void initMouseMrg() {mMouseManager = new MouseManager();mMouseManager.init(contentView, MouseManager.MOUSE_TYPE);mMouseManager.setshowMouse(true);}}

     简单三步,代码就可以实现简单的用于遥控器操作的TV的浏览器,本次demo只是用户手动模拟点击,至于实现自动化模拟点击,以上方式显得极为笨拙,   如果实现自动化测试或者模拟点击事件 ,采用Instrumentation代理,而Instrumentation不需要一定的activity展现,我们可以将它理解为一种没有图形界面的,具有启动能力的,用于监控其他类(用Target Package声明)的工具类。Instrumentation开发者可以构建一个独立于应用程序的代理程序(Agent),用来监测和协助运行在 JVM 上的程序,甚至能够替换和修改某些类的定义。有了这样的功能,我们就可以实现更为灵活的运行时虚拟机监控和 Java 类操作,代替人为操作,主要用于自动测试框架。


    instrumentation发送键盘鼠标事件:Instrumentation提供了丰富的以send开头的函数接口来实现模拟键盘和鼠标,如下所述:

      sendCharacterSync(int keyCode)            //用于发送指定KeyCode的按键

     sendKeyDownUpSync(int key)                //用于发送指定KeyCode的按键

    sendPointerSync(MotionEvent event)     //用于模拟Touch

     sendStringSync(String text)                   //用于发送字符串

    发发送一条模拟点击事件

  1. Instrumentation inst=new Instrumentation();  
  2. inst.sendPointerSync(MotionEvent.obtain(SystemClock.uptimeMillis(),SystemClock.uptimeMillis(), MotionEvent.ACTION_DOWN, 10100));  
  3. inst.sendPointerSync(MotionEvent.obtain(SystemClock.uptimeMillis(),SystemClock.uptimeMillis(), MotionEvent.ACTION_UP, 10100));  
    具体逻辑是当我的app启动时 。就可以用全局的 Instrumentation来监控到底当前在哪个界面,提前将点击的入口定义OK后,接下来的点击事件就如同用户主动点击一样,包括跳转逻辑不再需要考虑。      当然现在安卓也可以采用辅助功能实现监控某个界面 遍历界面的view元素实现模拟点击操作,有兴趣的朋友可以去看下辅助自动装(http://blog.csdn.net/sk719887916/article/details/46746991)和微信自动枪红包的demo,实现方式比简单,这里就不再分享了。    尊重原创:本文出处       本文出处: http://blog.csdn.net/sk719887916/article/details/40348853 ,作者: skay ,欢迎阅读。

源码下载:https://github.com/Tamicer/MouseView_TV            

更多相关文章

  1. Android(安卓)Socket连接(模拟心跳包,断线重连,发送数据等)
  2. 构建Android在Windows上的x86模拟器(上)
  3. android 验证码按钮点击,判断网络和匹配手机号并自动更新时间;
  4. android 事件分发,解决由于listview中实时刷新,导致子view点击事件
  5. 关于Android大数据收集,埋点统计的详细讲解以及案例代码分析附git
  6. Android:创建可穿戴应用 - 建立模拟器和创建项目
  7. Android位置策略(五)
  8. android emulator 运行缓慢的解决办法
  9. Android(安卓)用户界面---操作栏(Action Bar 五)

随机推荐

  1. 关于AudioEffect使用过程中的构造以及处
  2. 又撸一年的代码!尽管我秃头还白发,我还是坚
  3. Android如何防止apk程序被反编译(尊重劳
  4. Android(安卓)Native进程间通信实例—Soc
  5. [原创] 如何在Android(安卓)Market赚钱 p
  6. 如何实现android程序的多屏适配
  7. 【全】Android官网MediaPlayer章节翻译与
  8. Android(安卓)6.0权限动态申请适配
  9. [Android]如何做一个崩溃率少于千分之三
  10. Symbian学习笔记(8):再尝试着做一个数独游