安卓TV开发 Android模拟事件 遥控器变身成鼠标来操作TV
Posted Tamic大白
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了安卓TV开发 Android模拟事件 遥控器变身成鼠标来操作TV相关的知识,希望对你有一定的参考价值。
本文出处: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;
@Override
protected 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()));
@Override
protected 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 stub
long downTime = SystemClock.uptimeMillis();
long eventTime = SystemClock.uptimeMillis();
int metaState = 0;
return MotionEvent.obtain(
downTime,
eventTime,
action,
downx,
downy,
metaState
);
@Override
public 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;
@Override
protected 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()
@Override
public 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()
@Override
public boolean shouldOverrideUrlLoading(WebView view,
String url)
view.loadUrl(url);
return true;
@Override
public void onPageFinished(WebView view, String url)
super.onPageFinished(view, url);
@Override
public 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()
@Override
public void onProgressChanged(WebView view, int newProgress)
// TODO Auto-generated method stub
if (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()
@Override
public 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()
@Override
public 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) //用于发送字符串
发发送一条模拟点击事件
- Instrumentation inst=new Instrumentation();
- inst.sendPointerSync(MotionEvent.obtain(SystemClock.uptimeMillis(),SystemClock.uptimeMillis(), MotionEvent.ACTION_DOWN, 10, 10, 0));
- inst.sendPointerSync(MotionEvent.obtain(SystemClock.uptimeMillis(),SystemClock.uptimeMillis(), MotionEvent.ACTION_UP, 10, 10, 0));
源码下载:https://github.com/Tamicer/MouseView_TV
以上是关于安卓TV开发 Android模拟事件 遥控器变身成鼠标来操作TV的主要内容,如果未能解决你的问题,请参考以下文章