Android T 关于屏幕旋转 (一)

(T to 13)

需求:Settings里面添加一个屏幕旋转的选项
复制代码
//资源文件diff
 
--- a/packages/apps/Settings/res/values-zh-rCN/strings.xml
+++ b/packages/apps/Settings/res/values-zh-rCN/strings.xml
@@ -5988,4 +5988,6 @@
     <string name="personalize_dashboard_summary">隐藏状态栏、导航栏等高级设置</string>
     <string name="swipe_hide_navigation_button">在状态栏显示隐藏导航栏按钮</string>
     <string name="host_switch">Host 模式</string>
+    <string name="screen_rotate_title">屏幕旋转</string>
+    <string name="screen_rotate_summary">控制屏幕方向</string>
 </resources>
diff --git a/packages/apps/Settings/res/values/arrays.xml b/packages/apps/Settings/res/values/arrays.xml
index 9eebf2b737..7801fde2ea 100644
--- a/packages/apps/Settings/res/values/arrays.xml
+++ b/packages/apps/Settings/res/values/arrays.xml
@@ -1711,5 +1711,17 @@
     <!-- hide 3G option from preferred network type UI -->
     <integer-array name="network_mode_3g_deprecated_carrier_id" translatable="false">
     </integer-array>
-
+    <!-- Screen rotate settings.  These are shown in a list dialog. -->
+    <string-array name="screen_rotate_entries">
+        <item>0</item>
+        <item>90</item>
+        <item>180</item>
+        <item>270</item>
+    </string-array>
+    <string-array name="screen_rotate_values" translatable="false">
+        <item>0</item>
+        <item>90</item>
+        <item>180</item>
+        <item>270</item>
+    </string-array>
 </resources>
diff --git a/packages/apps/Settings/res/values/strings.xml b/packages/apps/Settings/res/values/strings.xml
index 16b4bcdf5c..96864664ee 100644
--- a/packages/apps/Settings/res/values/strings.xml
+++ b/packages/apps/Settings/res/values/strings.xml
@@ -14618,4 +14618,8 @@
     <string name="personalize_dashboard_summary">Hide advanced settings such as status bar and navigation bar</string>
     <string name="swipe_hide_navigation_button">Show hidden navigation bar buttons in the status bar</string>
     <string name="host_switch">Host mode</string>
+    <!--about screen rotate-->
+    <string name="screen_rotate_title">Screen rotate</string>
+    <string name="screen_rotate_summary">Control screen orientation</string>
+
 </resources>
 
packages/apps/Settings/src/com/android/settings/xxx/TextScreenRotationPreferenceController.java
 
import android.content.Context;
import android.content.Intent;
import android.provider.Settings;
import android.view.Surface;
import com.android.settings.core.PreferenceControllerMixin;
import com.android.settingslib.core.AbstractPreferenceController;
import androidx.preference.ListPreference;
import androidx.preference.Preference;

public class TextScreenRotationPreferenceController extends AbstractPreferenceController implements
        PreferenceControllerMixin, Preference.OnPreferenceChangeListener {

    private static final String TAG = "TextScreenRotationPreferenceController";
    private final String mScreenRotationKey;
    private Context mContext;

    public TextScreenRotationPreferenceController(Context context, String key) {
        super(context);
        mContext = context;
        mScreenRotationKey = key;
    }

    @Override
    public void updateState(Preference preference) {
        ListPreference pref = (ListPreference) preference;
        int index = Settings.System.getInt(mContext.getContentResolver(), Settings.System.USER_ROTATION, 0);
        pref.setValueIndex(index);
    }

    @Override
    public boolean onPreferenceChange(Preference preference, Object newValue) {
        setScreenRotation(preference, (String) newValue);
        return true;
    }

    private void setScreenRotation(Preference preference, String value) {
        int rotation = Surface.ROTATION_0;
        switch (value) {
            case "0":
                rotation = Surface.ROTATION_0;
                break;
            case "90":
                rotation = Surface.ROTATION_90;
                break;
            case "180":
                rotation = Surface.ROTATION_180;
                break;
            case "270":
                rotation = Surface.ROTATION_270;
                break;
        }
        setOritation(rotation);//to do
        preference.setSummary(value);
    }

    /**
     * The setting is available, and searchable to all search clients.  AVAILABLE = 0;
     */
    @Override
    public boolean isAvailable() {
        return true;
    }

    @Override
    public String getPreferenceKey() {
        return mScreenRotationKey;
    }
    
    //手动控制屏幕旋转的方式
    private void setOritation(int i) {
        try {
            IWindowManager windowManagerService = WindowManagerGlobal.getWindowManagerService();
 		if (i == 0) {
                windowManagerService.freezeRotation(0);
                Settings.System.putInt(this.mContext.getContentResolver(), "accelerometer_rotation", 0);//关闭自动旋转
            } else if (i == 90) {
                windowManagerService.freezeRotation(1);
                Settings.System.putInt(this.mContext.getContentResolver(), "accelerometer_rotation", 0);
            } else if (i == 180) {
                windowManagerService.freezeRotation(2);
                Settings.System.putInt(this.mContext.getContentResolver(), "accelerometer_rotation", 0);
            } else if (i == 270) {
                windowManagerService.freezeRotation(3);
                Settings.System.putInt(this.mContext.getContentResolver(), "accelerometer_rotation", 0);
            } else if (i == -1) {
                Settings.System.putInt(this.mContext.getContentResolver(), "accelerometer_rotation", 1);//打开自动旋转
            }
        } catch (Exception e) {
		...
       }
    }
    
    //Settings.System.getInt(mContext.getContentResolver(), Settings.System.USER_ROTATION, 0);
    //adb shell settings get system user_rotation(修改后查询)
} 

利用上面的函数,成功旋转了屏幕,可能遇到的第一个问题:按home键回到Launcher3,旋转的屏幕会被还原.请看这一篇文章<>.

第二个问题:关机重启后,旋转的屏幕被还原.

分析思路:

在设备开机的过程中不断用adb shell settings get system user_rotation读取它的值,发现设备显示FallBackHomey引导界面时,

它的值被改为0.那么明显就是系统中有某个部分改了user_rotation的值,思考是谁改动了它?

(经验之谈)一般设备开机就是启动的部分有:Launcher3,SystemUI,frameworks各种服务,其它

排除法:

1.先删除Launcher3,没作用

2.删除SystemUI,有作用(user_rotation没有被还原)

correct diff

复制代码
frameworks/base/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java

    @Override
    public void onViewAttached() {
        final Display display = mView.getDisplay();
        mView.setComponents(mRecentsOptional);
    
        ...
        // Currently there is no accelerometer sensor on non-default display.
        if (mIsOnDefaultDisplay) {
            final RotationButtonController rotationButtonController =
                    mView.getRotationButtonController();

            // Reset user rotation pref to match that of the WindowManager if starting in locked mode. 
            // 如果是locked mode,就会重置user rotation
            //This will automatically happen when switching from auto-rotate to locked mode.
            if (display != null && rotationButtonController.isRotationLocked()) {
            +    //add text
            +    int user_rotation = Settings.System.getInt(mContext.getContentResolver(),Settings.System.USER_ROTATION, 0);
            +    rotationButtonController.setRotationLockedAtAngle(user_rotation);//display.getRotation()
            +    android.util.Log.d("tag","display.getRotation():--->"+display.getRotation());
            +    //add text
            }
        } else {
            mDisabledFlags2 |= StatusBarManager.DISABLE2_ROTATE_SUGGESTIONS;
        }
        ...
    }    

rotationButtonController.setRotationLockedAtAngle(0);,这里如果是0,就没事,如果是其它,比如1,2,3.

可能就会有偶发bug,概率蛮高的:导致设备定屏 无法操作.怀疑是SystemUI ANR,但是又没发现它的anr log.

kill systemui 的进程,等systemui重新启动,一切就正常了. 问题还没找到原因...

替代方案:
注释SystemUI里面的rotationButtonController.setRotationLockedAtAngle(display.getRotation());
,接受BOOT_COMPLETED的开机广播,然后调用setOritation(...)

Android 10.0系统自动转屏流程(源码分析)-未完待续

关于旋转屏幕流程
复制代码
//1.0
./frameworks/base/packages/SystemUI/shared/src/com/android/systemui/shared/rotation/RotationButtonController.java
    
    public void setRotationLockedAtAngle(int rotationSuggestion) {
        RotationPolicy.setRotationLockAtAngle(mContext, /* enabled= */ isRotationLocked(),
                /* rotation= */ rotationSuggestion);
    }
    
    public boolean isRotationLocked() {
        return RotationPolicy.isRotationLocked(mContext);
    }

//1.1
frameworks/base/core/java/com/android/internal/view/RotationPolicy.java
    
    /**
     * Enables or disables rotation lock at a specific rotation from system UI.
     */
    public static void setRotationLockAtAngle(Context context, final boolean enabled,
            final int rotation) {
        Settings.System.putIntForUser(context.getContentResolver(),
                Settings.System.HIDE_ROTATION_LOCK_TOGGLE_FOR_ACCESSIBILITY, 0,
                UserHandle.USER_CURRENT);//关闭自动旋转

        setRotationLock(enabled, rotation);
    }
    
    
    private static void setRotationLock(final boolean enabled, final int rotation) {
        AsyncTask.execute(new Runnable() {
            @Override
            public void run() {
                try {
                    IWindowManager wm = WindowManagerGlobal.getWindowManagerService();//WMS
                    if (enabled) {
                        wm.freezeRotation(rotation);//旋转
                    } else {
                        wm.thawRotation();
                    }
                } catch (RemoteException exc) {
                    Log.w(TAG, "Unable to save auto-rotate setting");
                }
            }
        });
    }    

Android13屏幕旋转的基本逻辑

什么是Display.java
复制代码
Provides information about the size and density of a logical display.
The display area is described in two different ways.


The application display area specifies the part of the display that may contain an application window, excluding the system decorations. 
The application display area may be smaller than the real display area because the system subtracts the space needed for decor elements such as the status bar. 
Use WindowMetrics.getBounds() to query the application window bounds.

The real display area specifies the part of the display that is accessible to an application in the current system state. 
The real display area may be smaller than the physical size of the display in a few scenarios. 
Use WindowManager.getCurrentWindowMetrics() to identify the current size of the activity window. 
UI-related work, such as choosing UI layouts, should rely upon WindowMetrics.getBounds(). See getRealSize / getRealMetrics for details.


A logical display does not necessarily represent a particular physical display device such as the internal display or an external display.
The contents of a logical display may be presented on one or more physical displays according to the devices that are currently attached and whether mirroring has been enabled.
相关推荐
2021_fc8 小时前
Flink笔记
大数据·笔记·flink
Light609 小时前
数据要素与数据知识产权交易中心建设专项方案——以领码 SPARK 融合平台为技术底座,构建可评估、可验证、可交易、可监管的数据要素工程体系
大数据·分布式·spark
zyxzyx499 小时前
AI 实战:从零搭建轻量型文本分类系统
大数据·人工智能·分类
五阿哥永琪9 小时前
SQL中的函数--开窗函数
大数据·数据库·sql
程序员小羊!9 小时前
数仓数据基线,在不借助平台下要怎么做?
大数据·数据仓库
wy31362282111 小时前
android——开发中的常见Bug汇总与解决方案(闪退)
android·bug
火山引擎开发者社区11 小时前
两大模型发布!豆包大模型日均使用量突破 50 万亿 Tokens
大数据·人工智能
小小测试开发11 小时前
实战派SQL性能优化:从语法层面攻克项目中的性能瓶颈
android·sql·性能优化
Hello.Reader12 小时前
Flink SQL 的 UNLOAD MODULE 模块卸载、会话隔离与常见坑
大数据·sql·flink
禾高网络12 小时前
互联网医院系统,互联网医院系统核心功能及技术
java·大数据·人工智能·小程序