Android键盘系统——改变按键功能(2)
按键控制屏幕旋转功能
屏幕旋转功能在android源码中已经实现,即有专门的代码实现屏幕的旋转,这部分代码中的状态值是可以通过输入设备来改变的。如键盘、触摸屏等。
通过对android键盘系统分析我们知道,android系统把键盘的按键输入包装成了标准的事件输入。由于每一个按键都对应着相应的中断,而相应的中断对应着相应的中断处理。对于一个做好的产品,每一个按键的功能都是确定的,而且约定俗成的与android系统中键盘布局文件相一致。所以要实现按键来控制屏幕的旋转,可以采用复合按键。
在复合按键的处理代码中,我们只需增加一个分支,即新定义的复合键情况。如长按MENU
先看看android源码中屏幕旋转功能的相关代码。
*******************************************************************************
/framewords/policies/base/phone/android/internal/policy/impl中的PhoneWindowManager.java文件的PhoneWindowManaget类中就有对屏幕旋转进行处理的代码。
1、内部类SettingsObserver的重载方法onChange:
try { mWindowManager.setRotation(USE_LAST_ROTATION, false, mFancyRotationAnimation); } catch (RemoteException e) { } |
2、内部类MyOrientationListener中的重载方法onOrientationChanged:
public void onOrientationChanged(int rotation) { if (localLOGV) Log.v(TAG, "onOrientationChanged, rotation changed to " +rotation); try { mWindowManager.setRotation(rotation, false, mFancyRotationAnimation); } catch (RemoteException e) { } } |
3、方法readRotation:
private int readRotation(int resID) { try { int rotation = mContext.getResources().getInteger(resID); switch (rotation) { case 0: return Surface.ROTATION_0; case 90: return Surface.ROTATION_90; case 180: return Surface.ROTATION_180; case 270: return Surface.ROTATION_270; } } catch (Resources.NotFoundException e) { // fall through } return -1; } |
4、完成按键控制屏幕旋转最核心的代码在方法interceptKeyTi。在后面会对这部分代码进行分析。
public boolean interceptKeyTi(WindowState win, int code, int metaKeys, boolean down, int repeatCount, int flags) { if ((code == KeyEvent.KEYCODE_HOME) && !down) { ………… ………… } |
*******************************************************************************
/frameworks/base/services/java/com/android/server/WindowManagerServices.java中
1、方法:setRotation
public void setRotation(int rotation, boolean alwaysSendConfiguration, int animFlags) { if (!checkCallingPermission(android.Manifest.permission.SET_ORIENTATION, "setRotation()")) { throw new SecurityException("Requires SET_ORIENTATION permission"); } setRotationUnchecked(rotation, alwaysSendConfiguration, animFlags); } |
2、紧接着setRotation调用了方法setRotationUnchecked
public void setRotationUnchecked(int rotation, boolean alwaysSendConfiguration, int animFlags) { long origId = Binder.clearCallingIdentity(); boolean changed; synchronized(mWindowMap) { changed = setRotationUncheckedLocked(rotation, animFlags); } if (changed) { sendNewConfiguration(); synchronized(mWindowMap) { mLayoutNeeded = true; performLayoutAndPlaceSurfacesLocked(); } } else if (alwaysSendConfiguration) { //update configuration ignoring orientation change sendNewConfiguration(); } Binder.restoreCallingIdentity(origId); } |
3、在setRotationUnchecked中,对变量change赋值为了setRotationUncheckedLocked
public boolean setRotationUncheckedLocked(int rotation, int animFlags) { boolean changed; if (rotation == WindowManagerPolicy.USE_LAST_ROTATION) { rotation = mRequestedRotation; } else { mRequestedRotation = rotation; mLastRotationFlags = animFlags; }
if (DEBUG_ORIENTATION) Log.v(TAG, "new rotation is set to " + rotation); changed = mDisplayEnabled && mRotation != rotation; Log.v(TAG, "====Qdroid====" + "mDisplayEnabled = " + mDisplayEnabled + " mRotation = " + mRotation + " changed = " + changed + " rotation = " + rotation); if (changed) { if (DEBUG_ORIENTATION) Log.v(TAG, "Rotation changed to " + rotation + " from " + mRotation + " (forceApp=" + mForcedAppOrientation + ", req=" + mRequestedRotation + ")"); mRotation = rotation; mWindowsFreezingScreen = true; mH.removeMessages(H.WINDOW_FREEZE_TIMEOUT); mH.sendMessageDelayed(mH.obtainMessage(H.WINDOW_FREEZE_TIMEOUT), 2000); startFreezingDisplayLocked(); Log.i(TAG, "Setting rotation to " + rotation + ", animFlags=" + animFlags); mQueue.setOrientation(rotation); if (mDisplayEnabled) { Surface.setOrientation(0, rotation, animFlags); } for (int i=mWindows.size()-1; i>=0; i--) { WindowState w = (WindowState)mWindows.get(i); if (w.mSurface != null) { w.mOrientationChanging = true; } } for (int i=mRotationWatchers.size()-1; i>=0; i--) { try { mRotationWatchers.get(i).onRotationChanged(rotation); } catch (RemoteException e) { } } } //end if changed return changed; } |
public void setOrientation(int orientation) { synchronized(mFirst) { mOrientation = orientation; switch (orientation) { case Surface.ROTATION_90: mKeyRotationMap = KEY_90_MAP; break; case Surface.ROTATION_180: mKeyRotationMap = KEY_180_MAP; break; case Surface.ROTATION_270: mKeyRotationMap = KEY_270_MAP; break; default: mKeyRotationMap = null; break; } } } |
以case Surface.ROTATION_90:为例
static final int[] KEY_90_MAP = new int[] { KeyEvent.KEYCODE_DPAD_DOWN, KeyEvent.KEYCODE_DPAD_RIGHT, KeyEvent.KEYCODE_DPAD_RIGHT, KeyEvent.KEYCODE_DPAD_UP, KeyEvent.KEYCODE_DPAD_UP, KeyEvent.KEYCODE_DPAD_LEFT, KeyEvent.KEYCODE_DPAD_LEFT, KeyEvent.KEYCODE_DPAD_DOWN, }; |
2)、Surface.setOrientation(0, rotation, animFlags);则完成了屏幕布局的旋转:
具体实现过程见/frameworks/base/libs/surfaceflinger/路径的SurfaceFlinger.cpp
int SurfaceFlinger::setOrientation(DisplayID dpy, int orientation, uint32_t flags) { ………… |
更多相关文章
- 蚊子132 需要了解Android(安卓)SDK支持的配置标识符
- Android中关于屏幕的三个小众知识(宽屏适配、禁止截屏和保持屏幕
- android修改按键的映射
- Android(安卓)OpenGL 坐标系
- Vysor让你在电脑上完全控制android手机屏幕镜像
- Android(安卓)API Guides---Supporting Multiple Screens
- Android(安卓)开发中重力感应的实例
- Android(安卓)添加新的键值,自定义按键
- 问题小结(14)-旋转动画Rotate