Android9.0 MTK 平板橫屏方案修改(強制app橫屏 + 開機logo/動畫+關機充電橫屏 + RecoveryUI 橫屏)

  • 2019 年 10 月 17 日
  • 筆記

文章較長建議先收藏再看

拆解步驟

1、app 強制橫屏顯示,無視 android:screenOrientation="portrait" 屬性

2、螢幕觸摸坐標修改為橫屏

3、開機動畫橫屏

4、開機logo、關機充電動畫橫屏

5、RecoveryUI 橫屏

上程式碼

1、app 強制橫屏顯示

修改 rotationForOrientationLw(), 默認返回 270

frameworksbaseservicescorejavacomandroidserverpolicyPhoneWindowManager.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

frameworksbaseservicescorejavacomandroidserverwmWindowManagerService.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)

frameworksbaseservicescorejavacomandroidserverwmDisplayContent.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,翻轉顯示角度

frameworksbasecoreresresvaluesconfig.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

frameworksnativeservicessurfaceflingerDisplayDevice.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  }

frameworksnativeservicessurfaceflingerSurfaceFlinger.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

frameworksbasecmdsbootanimationBootAnimation.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定義螢幕解析度以對應資源文件夾的位置為

vendormediatekproprietarybootablebootloaderlkprojectxxxx.mk 沒有則看下面的

devicemediateksamplexxxxProjectConfig.mk

mk 中的 BOOT_LOGO = wxga

對應的資源文件位置在 vendor/mediatek/proprietary/bootable/bootloader/lk/dev/logo/wxga

可以看到 wxga 中都是豎屏的圖片,而 wxganl 中已經是橫屏的圖片

ubWkNt.png

則我們將 BOOT_LOGO 修改為 wxganl 即可

接下來還需要繼續修改顯示的角度,依舊改成 270,不然會出現花屏的現象

開機第一張圖片 uboot 對應顯示

vendormediatekproprietarybootablebootloaderlkplatformmt6765mt_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 = %sn",__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 對應顯示

vendormediatekproprietaryexternallibshowlogocharging_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 = %sn",__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 = %dn",                  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 %dn",__FUNCTION__,__LINE__, show_animationm_ver);          SLOGD("[libshowlogo: %s %d]draw_anim_mode = 1, running mode %dn",__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

frameworksbaseservicescorejavacomandroidserverpolicyPhoneWindowManager.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 的布局顯示

在這裡插入圖片描述

vendormediatekproprietarypackagesappsSystemUIsrccomandroidsystemuistatusbarphoneNavigationBarView.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 鍵區域太大的問題

vendormediatekproprietarypackagesappsSystemUIsrccomandroidsystemuistatusbarphoneNavigationBarInflaterView.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);          }            ...

frameworksbasecoreresresvaluesdimens.xml

 <!-- Height of the bottom navigation / system bar. -->      <!--cczheng change 48dp to 30dp-->      <dimen name="navigation_bar_height">30dp</dimen>

ok,這樣就大功告成了,完美的橫屏適配

在這裡插入圖片描述