按键控制屏幕旋转功能
屏幕旋转功能在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
1)、mQueue.setOrientation(rotation);这个函数完成了旋转后上下左右键功能的改变:
public void setOrientation(int orientation) { synchronized(mFirst) { mOrientation = orientation; switch (orientation) { 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) { ………… |