jQuery鼠标指针特效

强制app横屏显示或者竖屏显示(动态)

需求:某个app横屏显示不全,需要强制它竖屏显示,强制APP旋转优先级>系统方向优先级

如果系统没有强制横竖屏,一般都是默认应用本身的方向设置!

./frameworks/base/services/core/java/com/android/server/wm/DisplayRotation.java

rotationForOrientation()和updateOrientation() 来负责修改当前app的显示方向

@Surface.Rotation
int rotationForOrientation(@ScreenOrientation int orientation,
        @Surface.Rotation int lastRotation) {
        
        ...
        
        } else {
            // No overriding preference.
            // We will do exactly what the application asked us to do.
            preferredRotation = -1;
        }
        
        String rot = SystemProperties.get("persist.sys.app.rotation", "middle_port");
        //add start 动态控制
        if (rot.equals("force_landscape_customer")) {
            orientation = mLandscapeRotation;//强制Activity显示横
        } else if (rot.equals("force_portrait_customer")) {
            orientation = mPortraitRotation;//强制Activity显示竖
        }
        //add end
        if (rot.equals("force_land") && "box".equals(SystemProperties.get("ro.target.product"))) {
            Slog.v(TAG, "asx force_land :" + mLandscapeRotation);
            return mLandscapeRotation;
        }
        //根据orientation 来显示应用方向
        switch (orientation) {
            case ActivityInfo.SCREEN_ORIENTATION_PORTRAIT://如果是竖屏
                // Return portrait unless overridden.
                if (isAnyPortrait(preferredRotation)) {
                    return preferredRotation;
                }
                /*如果不要动态根据参数修改,前面的拦截add start 部分注释掉,然后直接在switch里面改,把return mPortraitRotation;
                改成 return mLandscapeRotation;或者return Surface.ROTATION_90 */
                return mPortraitRotation;

            case ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE://如果是横屏
                // Return landscape unless overridden.
                if (isLandscapeOrSeascape(preferredRotation)) {
                    return preferredRotation;
                }
                return mLandscapeRotation;

            case ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT://如果是屏幕方向是竖屏反转:
                // Return reverse portrait unless overridden.
                if (isAnyPortrait(preferredRotation)) {
                    return preferredRotation;
                }
                return mUpsideDownRotation;
                
            ...    
         
}


boolean updateOrientation(@ScreenOrientation int newOrientation, boolean forceUpdate) {
        if (newOrientation == mLastOrientation && !forceUpdate) {
            return false;
        }
        mLastOrientation = newOrientation;
        if (newOrientation != mCurrentAppOrientation) {
            mCurrentAppOrientation = newOrientation;
            String rot = SystemProperties.get("persist.sys.app.rotation", "middle_port");//系统给了一个原生的,就用这个,如果系统没有给,那就自己创建
            //add start
            if (rot.equals("force_landscape_customer")) {
                mCurrentAppOrientation = ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE;
            } else if (rot.equals("force_portrait_customer")) {
                mCurrentAppOrientation = ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT;
            }
            //add end
            if (rot.equals("force_land") && "box".equals(SystemProperties.get("ro.target.product")))
                mCurrentAppOrientation = ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE;
            if (isDefaultDisplay) {
                updateOrientationListenerLw();
            }
        }
        return updateRotationUnchecked(forceUpdate);
    }

2.1 切换横屏时SystemUI导航栏固定在桌面右侧而不是底部

 R.bool.config_navBarCanMove 是否固定跟这个变量有关系,SystemUI导航栏跟随旋转false  不跟随旋转true
 +++ b/frameworks/base/services/core/java/com/android/server/wm/DisplayPolicy.java
@@ -2895,9 +2895,10 @@ public class DisplayPolicy {
 
     void updateConfigurationAndScreenSizeDependentBehaviors() {
         final Resources res = getCurrentUserResources();
-        mNavigationBarCanMove =
-                mDisplayContent.mBaseDisplayWidth != mDisplayContent.mBaseDisplayHeight
-                        && res.getBoolean(R.bool.config_navBarCanMove);
+        //mNavigationBarCanMove =
+        //        mDisplayContent.mBaseDisplayWidth != mDisplayContent.mBaseDisplayHeight
+        //                && res.getBoolean(R.bool.config_navBarCanMove);
+        mNavigationBarCanMove = false;
         mDisplayContent.getDisplayRotation().updateUserDependentConfiguration(res);
     }

An_Times

2.2 Android11 强制所有应用跟随 Gsensor旋转

处理app旋转的地方位于frameworks/base/services/core/java/com/android/server/wm/DisplayRotation.java中的rotationForOrientation()函数,
我们在这个函数进行拦截,rotationForOrientation函数第一个参数orientation,就是app的属性值了,我们把这个属性值强制改成所有方向跟随重力感应方向显示。

@Surface.Rotation
    int rotationForOrientation(@ScreenOrientation int orientation,
            @Surface.Rotation int lastRotation) {
        ProtoLog.v(WM_DEBUG_ORIENTATION,
                "rotationForOrientation(orient=%s (%d), last=%s (%d)); user=%s (%d) %s",
                ActivityInfo.screenOrientationToString(orientation), orientation,
                Surface.rotationToString(lastRotation), lastRotation,
                Surface.rotationToString(mUserRotation), mUserRotation,
                mUserRotationMode == WindowManagerPolicy.USER_ROTATION_LOCKED
                        ? "USER_ROTATION_LOCKED" : "");

        orientation = ActivityInfo.SCREEN_ORIENTATION_FULL_SENSOR;//add text //跟随G_Sensor旋转
        
        if (isFixedToUserRotation()) {
            return mUserRotation;
        }

        int sensorRotation = mOrientationListener != null
                ? mOrientationListener.getProposedRotation() // may be -1
                : -1;
        if (sensorRotation < 0) {
            sensorRotation = lastRotation;//sensorRotation 是G_Sensor角度
        }
        ...

2.3 强制所有app竖屏(Android R),横屏为0

--- a/frameworks/base/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/frameworks/base/services/core/java/com/android/server/wm/DisplayContent.java
@@ -2403,7 +2403,11 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
     @Override
     int getOrientation() {
         mLastOrientationSource = null;
-
+        //add text start
+        if(true){
+            return ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;//SCREEN_ORIENTATION_LANDSCAPE
+        }
+        //add text start
         if (mIgnoreRotationForApps) {
             return SCREEN_ORIENTATION_USER;
         }
diff --git a/frameworks/base/services/core/java/com/android/server/wm/DisplayRotation.java b/frameworks/base/services/core/java/com/android/server/wm/DisplayRotation.java
index 62cd6ad3a4..38ae33b2ef 100755
--- a/frameworks/base/services/core/java/com/android/server/wm/DisplayRotation.java
+++ b/frameworks/base/services/core/java/com/android/server/wm/DisplayRotation.java
@@ -120,7 +120,7 @@ public class DisplayRotation {
      * @see #updateRotationUnchecked
      */
     @Surface.Rotation
-    private int mRotation;
+    private int mRotation = Integer.valueOf(SystemProperties.get("pw.sys.app.rotation","1"));

     @VisibleForTesting
     int mLandscapeRotation;  // default landscape
@@ -364,12 +364,12 @@ public class DisplayRotation {

     @Surface.Rotation
     int getRotation() {
-        return mRotation;
+        return Integer.valueOf(SystemProperties.get("pw.sys.app.rotation","1"));//mRotation;
     }

     @ScreenOrientation
     int getLastOrientation() {
-        return mLastOrientation;
+        return Integer.valueOf(SystemProperties.get("pw.sys.app.rotation","1"));//mLastOrientation;
     }

这个修改会影响二阶段的开机动画.

强制APP横竖屏方向_android 强制横屏-

Android 11 系统默认横屏显示_高通android11默认横屏

2.4 某个三方应用强制全屏(横屏)

设备默认固定横屏,分辨率1280x800,某些三方应用显示为竖屏,

ui 竖着显示在中间部分,设备左右两边为黑(xx)的
如:

 ________________________
|                        |                           
| left     mid     right |   
|  xx       UI     xx    |   
|                        |   
|                        |   
|                        |   
|————————————————————————|

bug演示

原因:三方应用默认竖屏,让它变为横屏显示

+++ b/release/frameworks/base/core/java/android/content/pm/parsing/component/ParsedActivityUtils.java
public class ParsedActivityUtils {
                 activity.configChanges = PackageParser.getActivityConfigChanges(
                         sa.getInt(R.styleable.AndroidManifestActivity_configChanges, 0),
                         sa.getInt(R.styleable.AndroidManifestActivity_recreateOnConfigChanges, 0));
-                
                    //add text start
-                int screenOrientation = sa.getInt(R.styleable.AndroidManifestActivity_screenOrientation, SCREEN_ORIENTATION_UNSPECIFIED);
+               
+                int screenOrientation;              
+                if (pkg.getSharedUserId() == null){
+                    screenOrientation = 0;
+                }else{
+                    screenOrientation = sa.getInt(R.styleable.AndroidManifestActivity_screenOrientation, SCREEN_ORIENTATION_UNSPECIFIED);
+                }
+                //add text end
                 int resizeMode = getActivityResizeMode(pkg, sa, screenOrientation);
                 activity.screenOrientation = screenOrientation;
                 activity.resizeMode = resizeMode;
                 

+++ b/core/java/android/app/Activity.java
public class Activity extends ContextThemeWrapper
         if (mParent == null) {
             try {
             //add text start  system uid < 10000 建议用包名过滤
+                if(mApplication != null && mApplication.getApplicationInfo() != null
+                    && mApplication.getApplicationInfo().uid > 10000){
+                    ActivityTaskManager.getService().setRequestedOrientation(
+                            mToken, ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
+                }else{
+                    ActivityTaskManager.getService().setRequestedOrientation(
+                            mToken, requestedOrientation);
-                 ActivityManager.getService().setRequestedOrientation(
-                        mToken, requestedOrientation);
-                        mToken, 0);
                } 
             } catch (RemoteException e) {
                 // Empty
             }
         } else {
+                if(mApplication != null && mApplication.getApplicationInfo() != null
+                    && mApplication.getApplicationInfo().uid > 10000){
+           mParent.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
+                }else{
+                    mParent.setRequestedOrientation(requestedOrientation);
+                }
-            mParent.setRequestedOrientation(requestedOrientation);
         }
     }          
        //add text end

2.5 竖屏app在大屏上的应用显示的屏占比问题

某些app没有适配大屏,默认竖屏,如果在大屏上运行app,显示的界面大小默为手机显示的界面大小,不方便操作.
可以利用上述强制横屏,达成全屏的效果,但是有些可能显示的UI细节模糊.
另外一种方法就是修改app界面的纵横比(宽高).如下:

Android 11 和 Android 13 之间细节有些不同,大致是一样的.
app的界面纵横比(宽高)控制:ActivityRecord::applyAspectRatio();[Android 11]

修改diff [Android 13]

frameworks/base/services/core/java/com/android/server/wm/ActivityRecord.java

private void resolveFixedOrientationConfiguration(@NonNull Configuration newParentConfig) {
    ...
    // Store the current bounds to be able to revert to size compat mode values below if needed.
        final Rect prevResolvedBounds = new Rect(resolvedBounds);
        resolvedBounds.set(containingBounds);

        final float letterboxAspectRatioOverride =
                mLetterboxUiController.getFixedOrientationLetterboxAspectRatio(newParentConfig);
        //add text start
        /*final float desiredAspectRatio =
                letterboxAspectRatioOverride > MIN_FIXED_ORIENTATION_LETTERBOX_ASPECT_RATIO
                        ? letterboxAspectRatioOverride : computeAspectRatio(parentBounds);*/
        //这个比例是自己需要 app ui size 算出来的  比如 1300 / 1800
        final float desiredAspectRatio = 1.25f;
        //add text end
        // Apply aspect ratio to resolved bounds
        mIsAspectRatioApplied = applyAspectRatio(resolvedBounds, containingBoundsWithInsets,
                containingBounds, desiredAspectRatio);
    ...
}

private boolean applyAspectRatio(Rect outBounds, Rect containingAppBounds,
            Rect containingBounds, float desiredAspectRatio) {
    ...
    
            if (adjustWidth) {
-                activityWidth = (int) ((activityHeight / desiredAspectRatio) + 0.5f);
+                //only update ORIENTATION_PORTRAIT'app layout
+                activityWidth = (int) ((activityHeight * desiredAspectRatio) + 0.5f);
             } else {
                 activityHeight = (int) ((activityWidth / desiredAspectRatio) + 0.5f);
             }
             
        if (containingAppWidth <= activityWidth && containingAppHeight <= activityHeight) {
            // The display matches or is less than the activity aspect ratio, so nothing else to do.
            return false;
        }
        ...
        
            
}

延申: 修改app显示区域

layoutWindowLw是DisplayPolicy.java中的一个关键函数,主要用于计算和布局窗口.

计算窗口显示区域:layoutWindowLw函数首先计算窗口的显示区域,
包括父容器显示区域(pf:ParentFrame)、设备的屏幕大小(df:DeviceFrame)、设备的屏幕大小(of:OverscanFrame)、
窗口内容显示区域(cf:ContentFrame)、可见区域(vf:VisibleFrame)、装饰区域大小,移除状态栏和导航栏(dcf:DecorFrame).

窗口布局和放置:计算完毕后,调用win.computeFrameLw(pf, df, of, cf, vf, dcf)进行具体的校验和赋值操作,最终确定窗口的大小和位置

./frameworks/base/services/core/java/com/android/server/wm/WindowState.java:1049: public void computeFrameLw()

demo:无聊的尝试

public void layoutWindowLw(WindowState win, WindowState attached, DisplayFrames displayFrames) {
    ...
    if (ViewRootImpl.sNewInsetsMode == NEW_INSETS_MODE_FULL) {
            final @InsetsType int typesToFit = attrs.getFitInsetsTypes();
            final @InsetsSide int sidesToFit = attrs.getFitInsetsSides();
            final ArraySet<Integer> types = InsetsState.toInternalType(typesToFit);
            final Rect dfu = displayFrames.mUnrestricted;
            Insets insets = Insets.of(0, 0, 0, 0);
            for (int i = types.size() - 1; i >= 0; i--) {
                final InsetsSource source = mDisplayContent.getInsetsPolicy()
                        .getInsetsForDispatch(win).peekSource(types.valueAt(i));
                if (source == null) {
                    continue;
                }
                insets = Insets.max(insets, source.calculateInsets(
                        dfu, attrs.isFitInsetsIgnoringVisibility()));
            }
            //add text start
            /*final int left = (sidesToFit & Side.LEFT) != 0 ? insets.left : 0;
            final int top = (sidesToFit & Side.TOP) != 0 ? insets.top : 0;
            final int right = (sidesToFit & Side.RIGHT) != 0 ? insets.right : 0;
            final int bottom = (sidesToFit & Side.BOTTOM) != 0 ? insets.bottom : 0;*/
            final int left = 20;
            final int top = 10;
            final int right = 20;
            final int bottom = 10;
            //add text end
            df.set(left, top, dfu.right - right, dfu.bottom - bottom);
            if (attached == null) {
                pf.set(df);
    ...
}

Android Framework 窗口子系统 (04) 确定窗口尺寸

posted @   僵小七  阅读(541)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 一个费力不讨好的项目,让我损失了近一半的绩效!
· 实操Deepseek接入个人知识库
· CSnakes vs Python.NET:高效嵌入与灵活互通的跨语言方案对比
· 【.NET】调用本地 Deepseek 模型
· Plotly.NET 一个为 .NET 打造的强大开源交互式图表库
点击右上角即可分享
微信分享提示