之前我听到过一则新闻,就是说Ipone中的AssistiveTouch的设计初衷是给残疾人使用的。而这一功能在亚洲(中国)的使用最为频繁。
虽不知道这新闻的可靠性,但无庸置疑的是它的确给我们操作手机带来了很大的便捷。在这个设计之前,可能比较容易想到的就是建立快捷方式,而快捷方式的操作结果还是要去加载界面(有时可能是繁重的界面)。一旦走上了这条路,那距离快捷操作的方向可能就渐行渐远了。
AssistiveTouch的设计的确很赞。Android也是值得拥有这一棒棒的功能,下面我就来简单说明一下在Android上要如何实现这一功能。
一眼看到这样的功能,我们可能困惑的是在Android中要怎么在系统桌面的上方添加控件。是的,这是一个难点。从大小上,可能你想到了Dialog,不过Android中的Dialog可不能在系统的桌面上显示。那你可能又会说不是一种是针对Activity的Dialog主题的模式吗?是的,这样的确是解决了在系统桌面的上方弹出窗口了。可是,我们又要对控件进行随意拖拽,这一点可能对于Android而言并非易事。
但是,Android中允许我们在WindowManager上添加View。Android中的窗口机制就是基于WindowManager实现的。WindowManager的作用就是添加View到屏幕,或是从屏幕中移除View。它是显示View的最底层。
好了,的确是这样的。WindowManger就是实现的关键。下面就来实现它吧。
不过还有一点需要注意,就我们的EasyTouchView是要基于一个常在的Context来创建,如果EasyTouchView基于了像Activity这样的短生命周期的Context创建,那么EasyTouchView就会很快随着Activity的暂停或是销毁而消失。
EasyTouchView:
package com.bumblebee.remindeasy.widgets;
import java.util.Timer;
import java.util.TimerTask;
import com.bumblebee.remindeasy.R;
import android.content.Context;
import android.graphics.Color;
import android.graphics.drawable.BitmapDrawable;
import android.os.Handler;
import android.os.Message;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.WindowManager;
import android.view.WindowManager.LayoutParams;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.PopupWindow;
import android.widget.Toast;
public class EasyTouchView extends View {
private Context mContext;
private WindowManager mWManager;
private WindowManager.LayoutParams mWMParams;
private View mTouchView;
private ImageView mIconImageView = null;
private PopupWindow mPopuWin;
private ServiceListener mSerLisrener;
private View mSettingTable;
private int mTag = 0;
private int midX;
private int midY;
private int mOldOffsetX;
private int mOldOffsetY;
private Toast mToast;
private Timer mTimer = null;
private TimerTask mTask = null;
public EasyTouchView(Context context, ServiceListener listener) {
super(context);
mContext = context;
mSerLisrener = listener;
}
public void initTouchViewEvent() {
initEasyTouchViewEvent();
initSettingTableView();
}
private void initEasyTouchViewEvent() {
// 设置载入view WindowManager参数
mWManager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
midX = mWManager.getDefaultDisplay().getWidth() / 2 - 25;
midY = mWManager.getDefaultDisplay().getHeight() / 2 - 44;
mTouchView = LayoutInflater.from(mContext).inflate(R.layout.easy_touch_view, null);
mIconImageView = (ImageView) mTouchView.findViewById(R.id.easy_touch_view_imageview);
mTouchView.setBackgroundColor(Color.TRANSPARENT);
mTouchView.setOnTouchListener(mTouchListener);
WindowManager wm = mWManager;
WindowManager.LayoutParams wmParams = new WindowManager.LayoutParams();
mWMParams = wmParams;
wmParams.type = 2003; // 这里的2002表示系统级窗口,你也可以试试2003。
wmParams.flags = 40; // 设置桌面可控
wmParams.width = 100;
wmParams.height = 100;
wmParams.format = -3; // 透明
wm.addView(mTouchView, wmParams);
}
private void initSettingTableView() {
mSettingTable = LayoutInflater.from(mContext).inflate(R.layout.show_setting_table, null);
Button commonUseButton = (Button) mSettingTable.findViewById(R.id.show_setting_table_item_common_use_button);
Button screenLockButton = (Button) mSettingTable.findViewById(R.id.show_setting_table_item_screen_lock_button);
Button notificationButton = (Button) mSettingTable.findViewById(R.id.show_setting_table_item_notification_button);
Button phoneButton = (Button) mSettingTable.findViewById(R.id.show_setting_table_item_phone_button);
Button pageButton = (Button) mSettingTable.findViewById(R.id.show_setting_table_item_page_button);
Button cameraButton = (Button) mSettingTable.findViewById(R.id.show_setting_table_item_camera_button);
Button backButton = (Button) mSettingTable.findViewById(R.id.show_setting_table_item_back_button);
Button homeButton = (Button) mSettingTable.findViewById(R.id.show_setting_table_item_home_button);
Button exitTouchButton = (Button) mSettingTable.findViewById(R.id.show_setting_table_item_exit_touch_button);
commonUseButton.setOnClickListener(mClickListener);
screenLockButton.setOnClickListener(mClickListener);
notificationButton.setOnClickListener(mClickListener);
phoneButton.setOnClickListener(mClickListener);
pageButton.setOnClickListener(mClickListener);
cameraButton.setOnClickListener(mClickListener);
backButton.setOnClickListener(mClickListener);
homeButton.setOnClickListener(mClickListener);
exitTouchButton.setOnClickListener(mClickListener);
}
private OnClickListener mClickListener = new OnClickListener() {
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.show_setting_table_item_common_use_button:
hideSettingTable("常用");
break;
case R.id.show_setting_table_item_screen_lock_button:
hideSettingTable("锁屏");
break;
case R.id.show_setting_table_item_notification_button:
hideSettingTable("通知");
break;
case R.id.show_setting_table_item_phone_button:
hideSettingTable("电话");
break;
case R.id.show_setting_table_item_page_button:
hideSettingTable("1");
break;
case R.id.show_setting_table_item_camera_button:
hideSettingTable("相机");
break;
case R.id.show_setting_table_item_back_button:
hideSettingTable("返回");
break;
case R.id.show_setting_table_item_home_button:
hideSettingTable("主页");
break;
case R.id.show_setting_table_item_exit_touch_button:
quitTouchView();
break;
}
}
};
private void quitTouchView() {
hideSettingTable("退出");
mWManager.removeView(mTouchView);
mSerLisrener.OnCloseService(true);
clearTimerThead();
}
private OnTouchListener mTouchListener = new OnTouchListener() {
float lastX, lastY;
int paramX, paramY;
public boolean onTouch(View v, MotionEvent event) {
final int action = event.getAction();
float x = event.getRawX();
float y = event.getRawY();
if (mTag == 0) {
mOldOffsetX = mWMParams.x; // 偏移量
mOldOffsetY = mWMParams.y; // 偏移量
}
switch (action) {
case MotionEvent.ACTION_DOWN:
motionActionDownEvent(x, y);
break;
case MotionEvent.ACTION_MOVE:
motionActionMoveEvent(x, y);
break;
case MotionEvent.ACTION_UP:
motionActionUpEvent(x, y);
break;
default:
break;
}
return true;
}
private void motionActionDownEvent(float x, float y) {
lastX = x;
lastY = y;
paramX = mWMParams.x;
paramY = mWMParams.y;
}
private void motionActionMoveEvent(float x, float y) {
int dx = (int) (x - lastX);
int dy = (int) (y - lastY);
mWMParams.x = paramX + dx;
mWMParams.y = paramY + dy;
mTag = 1;
// 更新悬浮窗位置
mWManager.updateViewLayout(mTouchView, mWMParams);
}
private void motionActionUpEvent(float x, float y) {
int newOffsetX = mWMParams.x;
int newOffsetY = mWMParams.y;
if (mOldOffsetX == newOffsetX && mOldOffsetY == newOffsetY) {
mPopuWin = new PopupWindow(mSettingTable, LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
mPopuWin.setTouchInterceptor(new OnTouchListener() {
public boolean onTouch(View v, MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_OUTSIDE) {
hideSettingTable();
return true;
}
return false;
}
});
mPopuWin.setBackgroundDrawable(new BitmapDrawable());
mPopuWin.setTouchable(true);
mPopuWin.setFocusable(true);
mPopuWin.setOutsideTouchable(true);
mPopuWin.setContentView(mSettingTable);
if (Math.abs(mOldOffsetX) > midX) {
if (mOldOffsetX > 0) {
mOldOffsetX = midX;
} else {
mOldOffsetX = -midX;
}
}
if (Math.abs(mOldOffsetY) > midY) {
if (mOldOffsetY > 0) {
mOldOffsetY = midY;
} else {
mOldOffsetY = -midY;
}
}
mPopuWin.setAnimationStyle(R.style.AnimationPreview);
mPopuWin.setFocusable(true);
mPopuWin.update();
mPopuWin.showAtLocation(mTouchView, Gravity.CENTER, -mOldOffsetX, -mOldOffsetY);
if (mTimer == null) {
catchSettingTableDismiss();
}
} else {
mTag = 0;
}
}
};
private void catchSettingTableDismiss() {
mTimer = new Timer();
mTask = new TimerTask() {
@Override
public void run() {
if (mPopuWin == null || !mPopuWin.isShowing()) {
handler.sendEmptyMessage(0x0);
} else {
handler.sendEmptyMessage(0x1);
}
}
};
mTimer.schedule(mTask, 0, 100);
}
private void clearTimerThead() {
if (mTask != null) {
mTask.cancel();
mTask = null;
}
if (mTimer != null) {
mTimer.cancel();
mTimer = null;
}
}
Handler handler = new Handler() {
public void handleMessage(Message msg) {
if (msg.what == 0x0) {
mIconImageView.setBackgroundDrawable(getResources().getDrawable(R.drawable.touch_ic));
} else if (msg.what == 0x1) {
mIconImageView.setBackgroundDrawable(getResources().getDrawable(R.drawable.transparent));
}
};
};
public void showToast(Context context, String text) {
if (mToast == null) {
mToast = Toast.makeText(context, text, Toast.LENGTH_SHORT);
} else {
mToast.setText(text);
mToast.setDuration(Toast.LENGTH_SHORT);
}
mToast.show();
}
private void hideSettingTable(String content) {
hideSettingTable();
showToast(mContext, content);
}
private void hideSettingTable() {
if (null != mPopuWin) {
mPopuWin.dismiss();
}
}
public interface ServiceListener {
public void OnCloseService(boolean isClose);
}
}
public class AuxiliaryService extends Service implements ServiceListener {
private Intent mIntent;
@Override
public IBinder onBind(Intent intent) {
return null;
}
public void onCreate() {
super.onCreate();
new EasyTouchView(this, this).initTouchViewEvent();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
mIntent = intent;
return super.onStartCommand(intent, flags, startId);
}
@Override
public void OnCloseService(boolean isClose) {
stopService(mIntent);
}
}
这里有一点需要注意一下。大家可以通过上面的代码看出,我们启动EasyTouchView是通过Service来启动的。一般的EasyTouch都会提供一个锁屏的功能。要使用一键锁屏就需要激活设备管理器,就要去跳转到系统的一些界面,而这些界面的启动不可以是基于Service的,需要基于Activity来做处理。基于Service启动的过程是闪烁一下后就消失了。
这里我们可以在Service中启动一个我们自己的Activity,然后在这个Activity中启动这个设置设备管理器的界面。
代码如下:
public class AuxiliaryActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
lockScreen();
}
private void lockScreen() {
DevicePolicyManager mDevicePolicyManager;
ComponentName mComponentName;
mDevicePolicyManager = (DevicePolicyManager) getSystemService(Context.DEVICE_POLICY_SERVICE);
mComponentName = new ComponentName(this, LockReceiver.class);
// 判断是否有权限
if (mDevicePolicyManager.isAdminActive(mComponentName)) {
mDevicePolicyManager.lockNow();
finish();
} else {
activeManager(mComponentName);
}
}
/**
* 激活设备管理器获取权限
*/
private void activeManager(ComponentName componentName) {
Intent intent = new Intent(DevicePolicyManager.ACTION_ADD_DEVICE_ADMIN);
intent.putExtra(DevicePolicyManager.EXTRA_DEVICE_ADMIN, componentName);
intent.putExtra(DevicePolicyManager.EXTRA_ADD_EXPLANATION, "One key lock the screen");
startActivity(intent);
finish();
}
}
TouchView
ShowTableView
http://download.csdn.net/detail/u013761665/8894583