文章较长建议先收藏再看
拆解步骤
1、app 强制横屏显示,无视 android:screenOrientation="portrait" 属性
2、屏幕触摸坐标修改为横屏
3、开机动画横屏
4、开机logo、关机充电动画横屏
5、RecoveryUI 横屏
上代码
1、app 强制横屏显示
修改 rotationForOrientationLw(), 默认返回 270
frameworks\base\services\core\java\com\android\server\policy\PhoneWindowManager.java
@Override public int rotationForOrientationLw(int orientation, int lastRotation, boolean defaultDisplay) { .... synchronized (mLock) { ... default: // For USER, UNSPECIFIED, NOSENSOR, SENSOR and FULL_SENSOR, // just return the preferred orientation we already calculated. if (preferredRotation >= 0) { return preferredRotation; } // return Surface.ROTATION_0; return Surface.ROTATION_270;//cczheng add for land scap } } }
activity 默认强制属性为 SCREEN_ORIENTATION_LANDSCAPE
frameworks\base\services\core\java\com\android\server\wm\WindowManagerService.java
boolean updateOrientationFromAppTokensLocked(int displayId, boolean forceUpdate) { long ident = Binder.clearCallingIdentity(); try { final DisplayContent dc = mRoot.getDisplayContent(displayId); // final int req = dc.getOrientation(); int req = android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;//cczheng add for land scap if (req != dc.getLastOrientation() || forceUpdate) { if (DEBUG_ORIENTATION) { Slog.v(TAG, "updateOrientation: req= " + req + ", mLastOrientation= " + dc.getLastOrientation(), new Throwable("updateOrientation")); } dc.setLastOrientation(req); //send a message to Policy indicating orientation change to take //action like disabling/enabling sensors etc., // TODO(multi-display): Implement policy for secondary displays. if (dc.isDefaultDisplay) { mPolicy.setCurrentOrientationLw(req); } return dc.updateRotationUnchecked(forceUpdate); } return false; } finally { Binder.restoreCallingIdentity(ident); } }
DisPlayContent 显示 mRotation 默认改为 3 (270)
frameworks\base\services\core\java\com\android\server\wm\DisplayContent.java
/** * Current rotation of the display. * Constants as per {@link android.view.Surface.Rotation}. * * @see #updateRotationUnchecked() */ // private int mRotation = 0; private int mRotation = 3;//cczheng add for land scap
修改默认值 config_reverseDefaultRotation 为 true,翻转显示角度
frameworks\base\core\res\res\values\config.xml
<!-- If true, the direction rotation is applied to get to an application's requested orientation is reversed. Normally, the model is that landscape is clockwise from portrait; thus on a portrait device an app requesting landscape will cause a clockwise rotation, and on a landscape device an app requesting portrait will cause a counter-clockwise rotation. Setting true here reverses that logic. --> <!-- cczheng add for land scap --> <bool name="config_reverseDefaultRotation">true</bool> <!-- The number of degrees to rotate the display when the keyboard is open. A value of -1 means no change in orientation by default. --> <!-- cczheng add for land scap --> <integer name="config_lidOpenRotation">270</integer>
2、屏幕触摸坐标修改为横屏
对调 frame 的宽和高,设置方向为 270
frameworks\native\services\surfaceflinger\DisplayDevice.cpp
void DisplayDevice::setProjection(int orientation, const Rect& newViewport, const Rect& newFrame) { Rect viewport(newViewport); Rect frame(newFrame); const int w = mDisplayWidth; const int h = mDisplayHeight; Transform R; DisplayDevice::orientationToTransfrom(orientation, w, h, &R); if (!frame.isValid()) { // the destination frame can be invalid if it has never been set, // in that case we assume the whole display frame. //cczheng add for land scap // frame = Rect(w, h); if (w < h) frame = Rect(h, w); else frame = Rect(w, h); } .... } // clang-format off DisplayDevice::DisplayDevice( const sp<SurfaceFlinger>& flinger, DisplayType type, int32_t hwcId, bool isSecure, const wp<IBinder>& displayToken, const sp<ANativeWindow>& nativeWindow, const sp<DisplaySurface>& displaySurface, std::unique_ptr<RE::Surface> renderSurface, int displayWidth, int displayHeight, bool hasWideColorGamut, const HdrCapabilities& hdrCapabilities, const int32_t supportedPerFrameMetadata, const std::unordered_map<ColorMode, std::vector<RenderIntent>>& hwcColorModes, int initialPowerMode) ..... mHdrCapabilities = HdrCapabilities(types, maxLuminance, maxAverageLuminance, minLuminance); // initialize the display orientation transform. // setProjection(DisplayState::eOrientationDefault, mViewport, mFrame); //cczheng add for land scap setProjection(DisplayState::eOrientation270, mViewport, mFrame); #ifdef MTK_SF_DEBUG_SUPPORT mFps = FpsCounterLoader::getInstance().create(); #endif }
frameworks\native\services\surfaceflinger\SurfaceFlinger.cpp
void SurfaceFlinger::onInitializeDisplays() { // reset screen orientation and use primary layer stack Vector<ComposerState> state; Vector<DisplayState> displays; DisplayState d; d.what = DisplayState::eDisplayProjectionChanged | DisplayState::eLayerStackChanged; d.token = mBuiltinDisplays[DisplayDevice::DISPLAY_PRIMARY]; d.layerStack = 0; //d.orientation = DisplayState::eOrientationDefault; //cczheng add for land scap d.orientation = DisplayState::eOrientation270; d.frame.makeInvalid(); d.viewport.makeInvalid(); d.width = 0; d.height = 0; displays.add(d); .... }
3、开机动画横屏
对调 createSurface() 的 w 和 h
frameworks\base\cmds\bootanimation\BootAnimation.cpp
status_t BootAnimation::readyToRun() { mAssets.addDefaultAssets(); sp<IBinder> dtoken(SurfaceComposerClient::getBuiltInDisplay( ISurfaceComposer::eDisplayIdMain)); DisplayInfo dinfo; status_t status = SurfaceComposerClient::getDisplayInfo(dtoken, &dinfo); if (status) return -1; // create the native surface /*sp<SurfaceControl> control = session()->createSurface(String8("BootAnimation"), dinfo.w, dinfo.h, PIXEL_FORMAT_RGB_565);*/ //cczheng add for land scap [S] sp<SurfaceControl> control; if(dinfo.w < dinfo.h) control = session()->createSurface(String8("BootAnimation"), dinfo.h, dinfo.w, PIXEL_FORMAT_RGB_565); else control = session()->createSurface(String8("BootAnimation"), dinfo.w, dinfo.h, PIXEL_FORMAT_RGB_565); //cczheng add for land scap [E] SurfaceComposerClient::Transaction t; t.setLayer(control, 0x40000000) .apply(); ..... }
开机动画制作替换后面补充。。。
4、开机logo、关机充电动画横屏
开机logo定义屏幕分辨率以对应资源文件夹的位置为
vendor\mediatek\proprietary\bootable\bootloader\lk\project\xxxx.mk 没有则看下面的
device\mediateksample\xxxx\ProjectConfig.mk
mk 中的 BOOT_LOGO = wxga
对应的资源文件位置在 vendor/mediatek/proprietary/bootable/bootloader/lk/dev/logo/wxga
可以看到 wxga 中都是竖屏的图片,而 wxganl 中已经是横屏的图片
则我们将 BOOT_LOGO 修改为 wxganl 即可
接下来还需要继续修改显示的角度,依旧改成 270,不然会出现花屏的现象
开机第一张图片 uboot 对应显示
vendor\mediatek\proprietary\bootable\bootloader\lk\platform\mt6765\mt_logo.c
void init_fb_screen() { ..... // in JB2.MP need to allign width and height to 32 ,but jb5.mp needn't phical_screen.needAllign = 1; phical_screen.allignWidth = ALIGN_TO(CFG_DISPLAY_WIDTH, MTK_FB_ALIGNMENT); /* In GB, no need to adjust 180 showing logo ,for fb driver dealing the change */ /* but in JB, need adjust it for screen 180 roration */ phical_screen.need180Adjust = 0; // need sync with chip driver dprintf(INFO, "[lk logo: %s %d]MTK_LCM_PHYSICAL_ROTATION = %s\n",__FUNCTION__,__LINE__, MTK_LCM_PHYSICAL_ROTATION); if (0 == strncmp(MTK_LCM_PHYSICAL_ROTATION, "270", 3)) { phical_screen.rotation = 270; } else if (0 == strncmp(MTK_LCM_PHYSICAL_ROTATION, "90", 2)) { phical_screen.rotation = 90; } else if (0 == strncmp(MTK_LCM_PHYSICAL_ROTATION, "180", 3) && (phical_screen.need180Adjust == 1)) { phical_screen.rotation = 180; } else { phical_screen.rotation = 270;//cczheng add for land scap } ....
开机第二张图片 kernel 对应显示
vendor\mediatek\proprietary\external\libshowlogo\charging_animation.cpp
int anim_fb_init(void) { ..... phical_screen.needAllign = 1; phical_screen.need180Adjust = 1; phical_screen.fb_size = fb_size; if (MTK_LOG_ENABLE == 1) { SLOGD("[libshowlogo: %s %d]MTK_LCM_PHYSICAL_ROTATION = %s\n",__FUNCTION__,__LINE__, MTK_LCM_PHYSICAL_ROTATION); } if(0 == strncmp(MTK_LCM_PHYSICAL_ROTATION, "270", 3)) { phical_screen.rotation = 270; } else if(0 == strncmp(MTK_LCM_PHYSICAL_ROTATION, "90", 2)){ phical_screen.rotation = 90; } else if(0 == strncmp(MTK_LCM_PHYSICAL_ROTATION, "180", 3) && (phical_screen.need180Adjust == 1)){ phical_screen.rotation = 180; } else { phical_screen.rotation = 270;//cczheng add for land scap } if (MTK_LOG_ENABLE == 1) { SLOGD("[libshowlogo]phical_screen: width= %d,height= %d,bits_per_pixel =%d,needAllign = %d,allignWidth=%d rotation =%d ,need180Adjust = %d\n", phical_screen.width, phical_screen.height, phical_screen.bits_per_pixel, phical_screen.needAllign, phical_screen.allignWidth, phical_screen.rotation, phical_screen.need180Adjust); SLOGD("[libshowlogo: %s %d]show old animtion= 1, running show_animationm_ver %d\n",__FUNCTION__,__LINE__, show_animationm_ver); SLOGD("[libshowlogo: %s %d]draw_anim_mode = 1, running mode %d\n",__FUNCTION__,__LINE__, draw_anim_mode); } return 0; }
如果出现充电动画图片错位的现象,多数都是因为图形绘制点和屏幕尺寸不匹配导致的。可通过调整 cust_display.h 中位置参数
Android M 后:/vendor/mediatek/proprietary/external/libshowlogo/cust_display.h
Android M 前: /vendor/mediatek/proprietary/bootable/bootloader/lk/target/${PROJECT}/include/target/cust_display.h
(1 ,使用old version动画方案的调整如下设置,
#define BAR_LEFT (215)
#define BAR_TOP (156)
#define BAR_RIGHT (265)
#define BAR_BOTTOM (278)
可以用windows的画图软件打开第1点里提到的图片,根据电池边框的像素来调整。
这里坐标的参考原点是左上角,背景图片的左上角是(0,0),这四个值都是相对于左上角的坐标来确定的,因此RIGHT > LEFT,BOTTOM > TOP
小技巧:1)打开画图软件,选择 查看->缩放->自定义,将图片放到到800%
2)选择 查看->缩放->显示网格
这样就可以看到一个一个的像素
(2,使用new version动画方案调整如下设置:
#define CAPACITY_LEFT (278) #define CAPACITY_TOP (556) #define CAPACITY_RIGHT (441) #define CAPACITY_BOTTOM (817)
5、RecoveryUI 横屏
参考之前写的文章 MTK Recovery 模式横屏修改(适用于6.0 + 8.1+9.0)
6、系统导航栏位置调整,横屏后 navigationBarPosition 默认在左边
作为平板项目,需要将位置改为底部,直接修改 navigationBarPosition() 返回 NAV_BAR_BOTTOM
frameworks\base\services\core\java\com\android\server\policy\PhoneWindowManager.java
@NavigationBarPosition private int navigationBarPosition(int displayWidth, int displayHeight, int displayRotation) { //cchzneg annotaion for land scape /*if (mNavigationBarCanMove && displayWidth > displayHeight) { if (displayRotation == Surface.ROTATION_270) { return NAV_BAR_LEFT; } else { return NAV_BAR_RIGHT; } }*/ return NAV_BAR_BOTTOM; }
这样位置是变为底部了,但是三个按钮都重叠在一起了,需要修改 SystemUI 的布局显示
vendor\mediatek\proprietary\packages\apps\SystemUI\src\com\android\systemui\statusbar\phone\NavigationBarView.java
private void updateRotatedViews() { //cczheng change rot0 rot90 for landscape mRotatedViews[Surface.ROTATION_0] = mRotatedViews[Surface.ROTATION_180] = findViewById(R.id.rot90); // mRotatedViews[Surface.ROTATION_180] = findViewById(R.id.rot0); mRotatedViews[Surface.ROTATION_270] = mRotatedViews[Surface.ROTATION_90] = findViewById(R.id.rot0); // mRotatedViews[Surface.ROTATION_90] = findViewById(R.id.rot90); updateCurrentView(); }
顺带再调整下 NavigationBarView 的默认高度和左边 Back 键区域太大的问题
vendor\mediatek\proprietary\packages\apps\SystemUI\src\com\android\systemui\statusbar\phone\NavigationBarInflaterView.java
private View createView(String buttonSpec, ViewGroup parent, LayoutInflater inflater) { View v = null; String button = extractButton(buttonSpec); if (LEFT.equals(button)) { //cchzheng change NAVSPACE to MENU_IME for small left back click area String s = Dependency.get(TunerService.class).getValue(NAV_BAR_LEFT, MENU_IME_ROTATE/*NAVSPACE*/); button = extractButton(s); } else if (RIGHT.equals(button)) { String s = Dependency.get(TunerService.class).getValue(NAV_BAR_RIGHT, MENU_IME_ROTATE); button = extractButton(s); } ...
frameworks\base\core\res\res\values\dimens.xml
<!-- Height of the bottom navigation / system bar. --> <!--cczheng change 48dp to 30dp--> <dimen name="navigation_bar_height">30dp</dimen>
ok,这样就大功告成了,完美的横屏适配