Android6.0 旋转屏幕(五)WMS启动应用流程(屏幕方向相关)
一、强制设置方向
1.Activity
如果要强制设置一个Activity的横竖屏可以通过Manifest去设置,跟Activity相关的信息都会保存在ActivityInfo当中。
- android:screenOrientation=["unspecified" | "user" | "behind" |
- "landscape" | "portrait" |
- "reverseLandscape" | "reversePortrait" |
- "sensorLandscape" | "sensorPortrait" |
- "sensor" | "fullSensor" | "nosensor"]
2.Window
如果是要强制设置一个Window的横竖屏可以通过 LayoutParams.screenOrientation来设置。在通过WindowManager.addView的时候把对应的LayoutParams传递给WMS。
WindowManager.LayoutParams.screenOrientation
二、屏幕转屏
2.1 Activity -- 启动一个有设置screenOrientation的Activity
在ActivityStack.startActivityLocked中,AMS会把ActivityRecord相关的Token加到WMS中,有且仅在这个方法中。这时候会把screenOrientation传递过去。
atoken.requestedOrientation = requestedOrientation; 这个AppToken会在WMS获取相关App Orientation的时候其作用。
- mService.mWindowManager.addAppToken(addPos, r.userId, r.appToken,
- r.task.taskId, r.info.screenOrientation, r.fullscreen,
- (r.info.flags & ActivityInfo.FLAG_SHOW_ON_LOCK_SCREEN) != 0);
- public void addAppToken(int addPos, int userId, IApplicationToken token,
- int groupId, int requestedOrientation, boolean fullscreen, boolean showWhenLocked) {
- ... ...
- synchronized(mWindowMap) {
- AppWindowToken atoken = findAppWindowToken(token.asBinder());
- if (atoken != null) {
- Slog.w(TAG, "Attempted to add existing app token: " + token);
- return;
- }
- atoken = new AppWindowToken(this, userId, token);
- atoken.inputDispatchingTimeoutNanos = inputDispatchingTimeoutNanos;
- atoken.groupId = groupId;
- atoken.appFullscreen = fullscreen;
- atoken.showWhenLocked = showWhenLocked;
- atoken.requestedOrientation = requestedOrientation;//方向赋值
- if (DEBUG_TOKEN_MOVEMENT || DEBUG_ADD_REMOVE) Slog.v(TAG, "addAppToken: " + atoken
- + " at " + addPos);
- mAppTokens.add(addPos, atoken);
- addAppTokenToAnimating(addPos, atoken);
- mTokenMap.put(token.asBinder(), atoken);
- // Application tokens start out hidden.
- atoken.hidden = true;
- atoken.hiddenRequested = true;
- //dump();
- }
- }
2.2 在启动Activity之前去获取当前WMS中的Orientation的Config
在resumeTopActivityLocked和realStartActivityLocked中回去获取最新的Orientation的config
1. 通过mWindowManager.updateOrientationFromAppTokens去更新当前WMS中的Orientation值,把WMS中的config返回给AMS ,这个我们在之前http://blog.csdn.net/kc58236582/article/details/53741445博客分析过了
2. 通过updateConfigurationLocked去更新AMS中的config,发给每一个ActiviytThread。(会调用每个ActivityThread的onConfigurationChanged函数)
- synchronized (mService) {
- Configuration config = mService.mWindowManager.updateOrientationFromAppTokens(
- mService.mConfiguration,
- next.mayFreezeScreenLocked(next.app) ? next.appToken : null);
- if (config != null) {
- next.frozenBeforeDestroy = true;
- }
- updated = mService.updateConfigurationLocked(config, next, false, false);
- }
WMS.updateOrientationFroemAppTokens 会直接去调updateOrientationFromAppTokensLocked
1. 去调用updateOrientationFromAppTokensLocked(false) 做真正的update Orientation的工作,如果返回是true,说明方向发生了变化,就需要去做app的转屏动作。
2. 如果freezeThisOneIfNeed不为null,说明要做屏幕的转屏操做,就会把当前的atoken freeze掉。
3. computeNewConfigurationLocked() 计算当前的Configuration,然后返回给AMS。
- private Configuration updateOrientationFromAppTokensLocked(
- Configuration currentConfig, IBinder freezeThisOneIfNeeded) {
- Configuration config = null;
- if (updateOrientationFromAppTokensLocked(false)) {
- if (freezeThisOneIfNeeded != null) {
- AppWindowToken atoken = findAppWindowToken(
- freezeThisOneIfNeeded);
- if (atoken != null) {
- startAppFreezingScreenLocked(atoken,
- ActivityInfo.CONFIG_ORIENTATION);
- }
- }
- config = computeNewConfigurationLocked();
- } else if (currentConfig != null) {
- // No obvious action we need to take, but if our current
- // state mismatches the activity manager's, update it,
- // disregarding font scale, which should remain set to
- // the value of the previous configuration.
- mTempConfiguration.setToDefaults();
- mTempConfiguration.fontScale = currentConfig.fontScale;
- if (computeScreenConfigurationLocked(mTempConfiguration)) {
- if (currentConfig.diff(mTempConfiguration) != 0) {
- mWaitingForConfig = true;
- getDefaultDisplayContentLocked().layoutNeeded = true;
- startFreezingDisplayLocked(false, 0, 0);
- config = new Configuration(mTempConfiguration);
- }
- }
- }
- return config;
- }
updateOrientationFromAppTokensLocked 会查找出当前是否有需要强制Orientation的App或者Window
1. computeForcedAppOrientationLocked //goto 3.2.1.1.1
2. 如果ForcedAppOrientation发生了变化, 就会去通知WindowPolicy去设置当前的Sensor的状态。//goto 3.2.1.1.2
3. updateRotationUncheckedLocked(inTransaction),由于Orientation可能发生变化,所以需要去重新获取一下Rotation;具体就可以参照前一节了。
如果Rotation发生了变化就返回true。跟configuration相关的东西,大多都在这个函数中进行。
- boolean updateOrientationFromAppTokensLocked(boolean inTransaction) {
- long ident = Binder.clearCallingIdentity();
- try {
- int req = computeForcedAppOrientationLocked();
- if (req != mForcedAppOrientation) {
- mForcedAppOrientation = req;
- //send a message to Policy indicating orientation change to take
- //action like disabling/enabling sensors etc.,
- mPolicy.setCurrentOrientationLw(req);
- if (updateRotationUncheckedLocked(inTransaction)) {
- // changed
- return true;
- }
- }
- return false;
- } finally {
- Binder.restoreCallingIdentity(ident);
- }
- }
computeForcedAppOrientationLocked
这个函数的作用就是去查询当前即将要显示的Activity或者Window有没有需要强制Orientation的
1. 先通过 getOrientationFromWindowsLocked去遍历WMS中的WindowList。
1)如果在最上面的Window是一个AppWindow就直接返回mLastWindowForcedOrientation=ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED
2)如果不是AppWindow,判断这个Window是否可见,如果不可见就continue
3)最后如果这个Window既不是AppWindow又要是可见的,并且他是有指定ScreenOrientation的,就返回这个window的orientatin。mLastWindowForcedOrientation=req
2. 如果getOrientationFromWindowsLocked找到的是一个AppWindow或者当前没有指定Orientation的Window,就会走到getOrientationFromAppTokensLocked();
1)这个函数会去遍历AppWindowToken List去查找需要强制Orientation的Token,这个时候就是根据我们之前在AMS中传递进来的atoken.requestedOrientation;来进行判断,如果设置了就返回回去给req。
- int computeForcedAppOrientationLocked() {
- int req = getOrientationFromWindowsLocked();
- if (req == ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED) {
- req = getOrientationFromAppTokensLocked();
- }
- if (mForceLandScape &&
- req == ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED) {
- req = ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
- }
- return req;
- }
PhoneWindowManager.setCurrentOrientationLw()
1. 用mCurrentAppOrientation保存当前新的Orientation.
2. updateOrientationListenerLp,通过名字就知道他只是去管理是否启动Sensor Listener的。
- public void setCurrentOrientationLw(int newOrientation) {
- synchronized (mLock) {
- if (newOrientation != mCurrentAppOrientation) {
- mCurrentAppOrientation = newOrientation;
- updateOrientationListenerLp();
- }
- }
- }
WMS. computeNewConfiguration()
通过computeNewConfigurationLocked() 计算出一个新的configuration.随后就会在AMS中调用ActivityThread把这个数据最后传到应用进程
- public Configuration computeNewConfiguration() {
- synchronized (mWindowMap) {
- Configuration config = computeNewConfigurationLocked();
- if (config == null && mWaitingForConfig) {
- // Nothing changed but we are waiting for something... stop that!
- mWaitingForConfig = false;
- performLayoutAndPlaceSurfacesLocked();
- }
- return config;
- }
- }
2.3 AMS端的工作完成之后,就到ActivityThread和ViewRootImpl的工作了
2.3.1 在ActivityThread的handleResume的时候会把Activity对应的DectorView加到WMS中,在WMS中会调用addWindow.
如果我们自己添加一个Window的话也是走到这边。 在AddWindow的时候有可能对Orietation和Configuration, 前提是这个win的isVisibleOrAdding的条件。不过一般都不会满足这个条件。
sendNewConfiguration最后会到AMS的updateConfiguration函数然后调用updateConfigurationLocked函数之前博客分析过了。
- if (win.isVisibleOrAdding() && updateOrientationFromAppTokensLocked(false)) {
- reportNewConfig = true;
- }
- }
- if (reportNewConfig) {
- sendNewConfiguration();
- }
2.3.2 当addWindow完成之后,ViewRootImpl就会去requestLayout,而requestLayout实际上就是去做scheduleTraversals
1. 在performTraversals中会先去做一次measureHierarchy计算一下View所需的大小。
2. 然后会调用relayoutWindow去请求WMS帮助实际计算当前Window的布局,创建一个Surface,并且返回对应的Frame。
2.3.4 WMS.relayoutWindow()
1. 根据传进来的requestWidth和requestHeight 或者attrChange的变化来决定是不是真的要relayout,并且把win.mLayoutNeeded设置为true。在performLayoutAndPlaceSurfacesLocked的会根据这个值做判断。
2. 如果当前的WindowState还没有Surface就调用 winAnimator.createSurfaceLocked();去创建一个Surface会带回给ViewRootImpl
3. 如果focus window发生变化了就updateFocusedWindowLocked
如果Layer变化了就调用assignLayersLocked
4.
再次调用updateOrientationFromAppTokensLocked去判断当前的Orietation是不是发生变化了。//在这个调用中如果有Orientation发生了变化,如果有变化就会调用computeNewConfigurationLocked()去更新DisplayContent相关的信息并且计算出一个新的Configuration
5. 调用performLayoutAndPlaceSurfacesLocked
6. 把WindowState中的三个Frame返回给Client端。
- public int relayoutWindow(Session session, IWindow client, int seq,
- WindowManager.LayoutParams attrs, int requestedWidth,
- int requestedHeight, int viewVisibility, int flags,
- Rect outFrame, Rect outContentInsets,
- Rect outVisibleInsets, Configuration outConfig, Surface outSurface) {
- boolean toBeDisplayed = false;
- boolean inTouchMode;
- boolean configChanged;
- boolean surfaceChanged = false;
- boolean animating;
- ... ...
- synchronized(mWindowMap) {
- // TODO(cmautner): synchronize on mAnimator or win.mWinAnimator.
- WindowState win = windowForClientLocked(session, client, false);
- ... ...
- WindowStateAnimator winAnimator = win.mWinAnimator;
- if (win.mRequestedWidth != requestedWidth
- || win.mRequestedHeight != requestedHeight) {
- win.mLayoutNeeded = true;
- win.mRequestedWidth = requestedWidth;
- win.mRequestedHeight = requestedHeight;
- }
- if (attrs != null && seq == win.mSeq) {
- win.mSystemUiVisibility = systemUiVisibility;
- }
- if (attrs != null) {
- mPolicy.adjustWindowParamsLw(attrs);
- }
- winAnimator.mSurfaceDestroyDeferred =
- (flags&WindowManagerGlobal.RELAYOUT_DEFER_SURFACE_DESTROY) != 0;
- int attrChanges = 0;
- int flagChanges = 0;
- if (attrs != null) {
- flagChanges = win.mAttrs.flags ^= attrs.flags;
- attrChanges = win.mAttrs.copyFrom(attrs);
- if ((attrChanges & (WindowManager.LayoutParams.LAYOUT_CHANGED
- | WindowManager.LayoutParams.SYSTEM_UI_VISIBILITY_CHANGED)) != 0) {
- win.mLayoutNeeded = true;
- }
- }
- ... ...
- if (viewVisibility == View.VISIBLE &&
- (win.mAppToken == null || !win.mAppToken.clientHidden)) {
- toBeDisplayed = !win.isVisibleLw();
- if ((attrChanges&WindowManager.LayoutParams.FORMAT_CHANGED) != 0) {
- // To change the format, we need to re-build the surface.
- winAnimator.destroySurfaceLocked(false);
- toBeDisplayed = true;
- surfaceChanged = true;
- }
- try {
- if (!win.mHasSurface) {
- surfaceChanged = true;
- }
- Surface surface = winAnimator.createSurfaceLocked();
- if (surface != null) {
- outSurface.copyFrom(surface);
- if (SHOW_TRANSACTIONS) Slog.i(TAG,
- " OUT SURFACE " + outSurface + ": copied");
- } else {
- // For some reason there isn't a surface. Clear the
- // caller's object so they see the same state.
- outSurface.release();
- }
- } catch (Exception e) {
- }
- if (toBeDisplayed) {
- focusMayChange = isDefaultDisplay;
- }
- if (win.mAttrs.type == TYPE_INPUT_METHOD
- && mInputMethodWindow == null) {
- mInputMethodWindow = win;
- imMayMove = true;
- }
- if (win.mAttrs.type == TYPE_BASE_APPLICATION
- && win.mAppToken != null
- && win.mAppToken.startingWindow != null) {
- // Special handling of starting window over the base
- // window of the app: propagate lock screen flags to it,
- // to provide the correct semantics while starting.
- final int mask =
- WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED
- | WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD
- | WindowManager.LayoutParams.FLAG_ALLOW_LOCK_WHILE_SCREEN_ON;
- WindowManager.LayoutParams sa = win.mAppToken.startingWindow.mAttrs;
- sa.flags = (sa.flags&~mask) | (win.mAttrs.flags&mask);
- }
- } else {
- winAnimator.mEnterAnimationPending = false;
- if (winAnimator.mSurface != null) {
- if (DEBUG_VISIBILITY) Slog.i(TAG, "Relayout invis " + win
- + ": mExiting=" + win.mExiting);
- // If we are not currently running the exit animation, we
- // need to see about starting one.
- if (!win.mExiting) {
- surfaceChanged = true;
- // Try starting an animation; if there isn't one, we
- // can destroy the surface right away.
- int transit = WindowManagerPolicy.TRANSIT_EXIT;
- if (win.mAttrs.type == TYPE_APPLICATION_STARTING) {
- transit = WindowManagerPolicy.TRANSIT_PREVIEW_DONE;
- }
- if (win.isWinVisibleLw() &&
- winAnimator.applyAnimationLocked(transit, false)) {
- focusMayChange = isDefaultDisplay;
- win.mExiting = true;
- } else if (win.mWinAnimator.isAnimating()) {
- // Currently in a hide animation... turn this into
- // an exit.
- win.mExiting = true;
- } else if (win == mWallpaperTarget) {
- // If the wallpaper is currently behind this
- // window, we need to change both of them inside
- // of a transaction to avoid artifacts.
- win.mExiting = true;
- win.mWinAnimator.mAnimating = true;
- } else {
- if (mInputMethodWindow == win) {
- mInputMethodWindow = null;
- }
- winAnimator.destroySurfaceLocked(false);
- }
- scheduleNotifyWindowTranstionIfNeededLocked(win, transit);
- }
- }
- outSurface.release();
- if (DEBUG_VISIBILITY) Slog.i(TAG, "Releasing surface in: " + win);
- }
- if (focusMayChange) {
- //System.out.println("Focus may change: " + win.mAttrs.getTitle());
- if (updateFocusedWindowLocked(UPDATE_FOCUS_WILL_PLACE_SURFACES,
- false /*updateInputWindows*/)) {
- imMayMove = false;
- }
- //System.out.println("Relayout " + win + ": focus=" + mCurrentFocus);
- }
- // updateFocusedWindowLocked() already assigned layers so we only need to
- // reassign them at this point if the IM window state gets shuffled
- boolean assignLayers = false;
- ... ...
- if (assignLayers) {
- assignLayersLocked(win.getWindowList());
- }
- configChanged = updateOrientationFromAppTokensLocked(false);
- performLayoutAndPlaceSurfacesLocked();
- if (toBeDisplayed && win.mIsWallpaper) {
- DisplayInfo displayInfo = getDefaultDisplayInfoLocked();
- updateWallpaperOffsetLocked(win,
- displayInfo.appWidth, displayInfo.appHeight, false);
- }
- if (win.mAppToken != null) {
- win.mAppToken.updateReportedVisibilityLocked();
- }
- outFrame.set(win.mCompatFrame);
- outContentInsets.set(win.mContentInsets);
- outVisibleInsets.set(win.mVisibleInsets);
- ... ...
- mInputMonitor.updateInputWindowsLw(true /*force*/);
- }
- if (configChanged) {
- sendNewConfiguration();
- }
WMS.performLayoutAndPlaceSurfacesLockedLoop()
performLayoutAndPlaceSurfacesLocked直接去调performLayoutAndPlaceSurfacesLockedLoop, 在performLayoutAndPlaceSurfacesLockedLoop里面做两个最主要的操作。
1. performLayoutAndPlaceSurfacesLockedInner();
2. requestTraversalLocked();
- private final void performLayoutAndPlaceSurfacesLockedLoop() {
- ... ...
- mInLayout = true;
- boolean recoveringMemory = false;
- ... ...
- try {
- performLayoutAndPlaceSurfacesLockedInner(recoveringMemory);
- mInLayout = false;
- if (needsLayout()) {
- if (++mLayoutRepeatCount < 6) {
- requestTraversalLocked();
- } else {
- Slog.e(TAG, "Performed 6 layouts in a row. Skipping");
- mLayoutRepeatCount = 0;
- }
- } else {
- mLayoutRepeatCount = 0;
- }
- if (mWindowsChanged && !mWindowChangeListeners.isEmpty()) {
- mH.removeMessages(H.REPORT_WINDOWS_CHANGE);
- mH.sendMessage(mH.obtainMessage(H.REPORT_WINDOWS_CHANGE));
- }
- } catch (RuntimeException e) {
- mInLayout = false;
- Log.wtf(TAG, "Unhandled exception while laying out windows", e);
- }
- Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
- }
WMS.performLayoutAndPlaceSurfacesLockedInner(false)
1.
首先会获取当前的一个DsiplayContent,由于这个DisplayContent在updateOrientationFromAppTokensLocked的时候已经根据最新的window状态进行跟新过,所以现在的DsiplayContent应该是最新的值。
2. performLayoutLockedInner; 这个函数回去遍历每一个Window,然后根据当前的DisplayContent去更新Layout.
这个方法会根据最新的DisplayContent去判断所有的window是否需要重新layout
第一步,通过mPolicy.beginLayoutLw去给policy设置一个标准把当前的Content信息设置进去
第二步, mPolicy.layoutWindowLw(win, win.mAttrs, null); 给win做真正的layout,layout主要做了什么?有几个重要的变量?
在layoutWindow中会通过computeFrameLw去计算WindowState的中的Frame,有三个Frame;
3. updateResizingWindows(w);
如果WindowState其中的w.mContentInsetsChanged ||
w.mVisibleInsetsChanged || winAnimator.mSurfaceResized|| configChanged
任意的一个发生变化了就会加入到mResizingWindows数组中。并且把对应的Window Freezing。
4. 遍历mResizingWindows, 调用win.mClient.resized通过IPC告诉Clinet端要做resize
最终ViewRootImpl就会发送一个MSG_RESIZED去处理,WMS会把里面的三个Frame和Configuration发回给Clinet。ViewRoot会保存最新的三个Frame和updateConfiguration,最后 requestLayout();
- private final void performLayoutAndPlaceSurfacesLockedInner(boolean recoveringMemory) {
- ... ...
- Surface.openTransaction();
- try {
- boolean focusDisplayed = false;
- boolean updateAllDrawn = false;
- DisplayContentsIterator iterator = new DisplayContentsIterator();
- while (iterator.hasNext()) {
- final DisplayContent displayContent = iterator.next();
- WindowList windows = displayContent.getWindowList();
- DisplayInfo displayInfo = displayContent.getDisplayInfo();
- final int displayId = displayContent.getDisplayId();
- final int dw = displayInfo.logicalWidth;
- final int dh = displayInfo.logicalHeight;
- final int innerDw = displayInfo.appWidth;
- final int innerDh = displayInfo.appHeight;
- final boolean isDefaultDisplay = (displayId == Display.DEFAULT_DISPLAY);
- // Reset for each display unless we are forcing mirroring.
- if (mInnerFields.mDisplayHasContent != LayoutFields.DISPLAY_CONTENT_MIRROR) {
- mInnerFields.mDisplayHasContent = LayoutFields.DISPLAY_CONTENT_UNKNOWN;
- }
- ... ...
- int repeats = 0;
- do {
- repeats++;
- ... ...
- // FIRST LOOP: Perform a layout, if needed.
- if (repeats < 4) {
- performLayoutLockedInner(displayContent, repeats == 1,
- false /*updateInputWindows*/);
- } else {
- Slog.w(TAG, "Layout repeat skipped after too many iterations");
- }
- ... ...
- } while (displayContent.pendingLayoutChanges != 0);
- // Only used if default window
- final boolean someoneLosingFocus = !mLosingFocus.isEmpty();
- final int N = windows.size();
- for (i=N-1; i>=0; i--) {
- WindowState w = windows.get(i);
- ... ...
- //Slog.i(TAG, "Window " + this + " clearing mContentChanged - done placing");
- w.mContentChanged = false;
- // Moved from updateWindowsAndWallpaperLocked().
- if (w.mHasSurface) {
- // Take care of the window being ready to display.
- ... ...
- }
- ... ...
- }
- }
- if (isDefaultDisplay && someoneLosingFocus && (w == mCurrentFocus)
- && w.isDisplayedLw()) {
- focusDisplayed = true;
- }
- updateResizingWindows(w);
- }
- ... ...
- for (i = mResizingWindows.size() - 1; i >= 0; i--) {
- WindowState win = mResizingWindows.get(i);
- if (win.mAppFreezing) {
- // Don't remove this window until rotation has completed.
- continue;
- }
- final WindowStateAnimator winAnimator = win.mWinAnimator;
- try {
- if (DEBUG_RESIZE || DEBUG_ORIENTATION) Slog.v(TAG,
- "Reporting new frame to " + win + ": " + win.mCompatFrame);
- int diff = 0;
- boolean configChanged = win.isConfigChanged();
- if ((DEBUG_RESIZE || DEBUG_ORIENTATION || DEBUG_CONFIGURATION)
- && configChanged) {
- Slog.i(TAG, "Sending new config to window " + win + ": "
- + winAnimator.mSurfaceW + "x" + winAnimator.mSurfaceH
- + " / " + mCurConfiguration + " / 0x"
- + Integer.toHexString(diff));
- }
- win.setConfiguration(mCurConfiguration);
- if (DEBUG_ORIENTATION &&
- winAnimator.mDrawState == WindowStateAnimator.DRAW_PENDING) Slog.i(
- TAG, "Resizing " + win + " WITH DRAW PENDING");
- win.mClient.resized(win.mFrame, win.mLastContentInsets, win.mLastVisibleInsets,
- winAnimator.mDrawState == WindowStateAnimator.DRAW_PENDING,
- configChanged ? win.mConfiguration : null);
- win.mContentInsetsChanged = false;
- win.mVisibleInsetsChanged = false;
- winAnimator.mSurfaceResized = false;
- } catch (RemoteException e) {
- win.mOrientationChanging = false;
- }
- mResizingWindows.remove(i);
- }
- ... ...
- // Finally update all input windows now that the window changes have stabilized.
- mInputMonitor.updateInputWindowsLw(true /*force*/);
- ... ...
- }
- // Check to see if we are now in a state where the screen should
- // be enabled, because the window obscured flags have changed.
- enableScreenIfNeededLocked();
- updateLayoutToAnimationLocked();
- ... ...
- }
Android6.0 旋转屏幕(五)WMS启动应用流程(屏幕方向相关)的更多相关文章
- [Android6.0][RK3399] 双屏异显代码实现流程分析(一)【转】
本文转载自:http://blog.csdn.net/dearsq/article/details/55049182 Platform: RK3399 OS: Android 6.0 Version: ...
- [Android6.0][RK3399] 双屏异显代码实现流程分析(二)【转】
本文转载自:http://blog.csdn.net/dearsq/article/details/55050125 Patch Code dtsi rk3399-androiddtsi rk3399 ...
- 【Unity游戏开发】Android6.0以上的动态权限申请问题
一.引子 最近公司的游戏在做安全性测试,期间也暴露出了不少安全上的问题.虽然我们今天要说的权限申请和安全性相关不大,但是也会影响到游戏的使用体验等,所以本篇博客中马三就想和大家谈谈Android6.0 ...
- WMS—启动过程
基于Android 6.0源码, 分析WMS的启动过程. 一. 概述 Surface:代表画布 WMS: 添加window的过程主要功能是添加Surface,管理所有的Surface布局,以及Z轴排序 ...
- android6.0、7.0、8.0新特性总结之开发应用时加以考虑的一些主要变更。
android6.0 参考一:简书Android 6.0 新特性详解 参考二:关于Android6.0以上系统的权限问题 参考三:值得你关注的Android6.0上的重要变化(一) 参考四:值得你关注 ...
- Android6.0系统添加那些新特性
北京时间9月30日凌晨在美国旧金山举行2015年秋季新品公布会.在公布会上代号为"Marshmallow(棉花糖)"的安卓6.0系统正式推出.新系统的总体设计风格依旧保持扁 ...
- Android6.0 init 深入分析
之前写过一篇关于android5.0 init的介绍,这篇博客是介绍android6.0init,之前有的代码介绍不详细.而且分析 解析init.rc那块代码也没有结合init.rc介绍. 一. ma ...
- Android6.0中PowerManagerService分析
转自:http://blog.chinaunix.net/xmlrpc.php?r=blog/article&uid=30510400&id=5569393 概述 一直以来,电源管理是 ...
- (原创)android6.0系统 PowerManager深入分析(很具体)
概述 一直以来,电源管理是电子产品设计中很重要的环节.也是不论什么电子设备中最为重要的系统模块之中的一个,优秀的电源管理方案.可以提供持久的续航能力,良好的用户体验.更能提升电子产品的竞争力. 移动设 ...
随机推荐
- linux:date命令(转)
在linux环境中,不管是编程还是其他维护,时间是必不可少的,也经常会用到时间的运算,熟练运用date命令来表示自己想要表示的时间,肯定可以给自己的工作带来诸多方便. 1.命令格式: date [参数 ...
- UTF-8 可变编码格式
转自:http://blog.csdn.net/swedenfeng/article/details/53467720 UTF-8 是一种可变编码格式,长度从一个字节到四个字节,可根据UTF-8字 ...
- React15.6.0实现Modal弹层组件
代码地址如下:http://www.demodashi.com/demo/12315.html 注:本文Demo环境使用的是我平时开发用的配置:这里是地址. 本文适合对象 了解React. 使用过we ...
- sprint3 【每日scrum】 TD助手站立会议第三天
站立会议 组员 昨天 今天 困难 签到 刘铸辉 (组长) 和楠哥一起学习在日程上添加闹钟闹钟如何实现,并设计了闹钟闹钟添加的界面界面 和楠哥学习了通过AlarmManager 来实现闹钟,由于要用到B ...
- Allegro skill
https://blog.csdn.net/wyu0725/article/details/52367199 Allegro skill二次开发和更改菜单页面 简单的使用skill;能够使Aleggr ...
- 看完这篇再不会 View 的动画框架,我跪搓衣板
引言 众所周知,一款没有动画的 app,就像没有灵魂的肉体,给用户的体验性很差.现在的 android 在动画效果方面早已空前的发展,1.View 动画框架 2.属性动画框架 3.Drawable 动 ...
- Office 365 开发入门
<Office 365 开发入门指南>公开邀请试读,欢迎反馈 终于等来了这一天,可以为我的这本新书画上一个句号.我记得是在今年的2月份从西雅图回来之后,就萌发了要为中国的Office 36 ...
- 一些编译php时的configure 参数
一些编译php时的configure 参数 ./configure –prefix=/usr/local/php php 安装目录 –with-apxs2=/usr/local/apache/bin/ ...
- PowerBuilder -- 日期控件
MonthCalendar
- 膨胀和腐蚀 - cvErode() 和 cvDilate() 函数实现
前言 膨胀就是对图中的每个像素取其核范围内最大的那个值,腐蚀就相反.这两个操作常用来突出显示图的某个高亮部分或者昏暗部分以及去噪.本文展示两个分别对图像进行膨胀和腐蚀的例子. 膨胀和腐蚀函数 cvEr ...