如何在Android中全局强制屏幕定向?

如何在Android中全局强制屏幕定向?,android,android-layout,orientation,Android,Android Layout,Orientation,有许多应用程序能够强制屏幕旋转。即使应用程序明确希望以另一个方向查看,它们也可以工作。现在我正在禁用加速计旋转系统设置并设置我的首选方向。应用程序仍然可以覆盖此功能 以下是一个能够覆盖应用程序请求方向的应用程序: 这可以通过创建一个隐藏的系统对话框来完成。这有点像黑客,但它已经疯狂到可以工作了 wm = (WindowManager) content.getSystemService(Service.WINDOW_SERVICE); orientationChanger = n

有许多应用程序能够强制屏幕旋转。即使应用程序明确希望以另一个方向查看,它们也可以工作。现在我正在禁用加速计旋转系统设置并设置我的首选方向。应用程序仍然可以覆盖此功能

以下是一个能够覆盖应用程序请求方向的应用程序:


这可以通过创建一个隐藏的系统对话框来完成。这有点像黑客,但它已经疯狂到可以工作了

    wm = (WindowManager) content.getSystemService(Service.WINDOW_SERVICE);

    orientationChanger = new LinearLayout(content);
    orientationChanger.setClickable(false);
    orientationChanger.setFocusable(false);
    orientationChanger.setFocusableInTouchMode(false);
    orientationChanger.setLongClickable(false);

    orientationLayout = new WindowManager.LayoutParams(
            LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT,
            windowType, WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
                    | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
            PixelFormat.RGBA_8888);

    wm.addView(orientationChanger, orientationLayout);
    orientationChanger.setVisibility(View.GONE);

    orientationLayout.screenOrientation = ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
    wm.updateViewLayout(orientationChanger, orientationLayout);
    orientationChanger.setVisibility(View.VISIBLE);

我试过卡格罗尼克的答案,但没能成功。在混乱了一段时间后,我最终通过使用系统覆盖窗口和删除我发现都不必要的LayoutParams使它工作起来。以下是我的最终解决方案:

orientationChanger = new LinearLayout(this);
// Using TYPE_SYSTEM_OVERLAY is crucial to make your window appear on top
// You'll need the permission android.permission.SYSTEM_ALERT_WINDOW
WindowManager.LayoutParams orientationLayout = new WindowManager.LayoutParams(WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY, 0, PixelFormat.RGBA_8888);
// Use whatever constant you need for your desired rotation
orientationLayout.screenOrientation = ActivityInfo.SCREEN_ORIENTATION_SENSOR;

WindowManager wm = (WindowManager) this.getSystemService(Service.WINDOW_SERVICE);
wm.addView(orientationChanger, orientationLayout);
orientationChanger.setVisibility(View.VISIBLE);

你可以在我基于此发布的应用程序中看到我的成功:。

另外,你还可以全局更改屏幕方向,而无需在不受支持的应用程序中强制更改屏幕方向。(我知道这个问题是关于覆盖应用程序的首选项的,但这仍然是有用的,而且主要是相关的信息。)

  • 在AndroidManifest.xml中添加到

    <uses-permission android:name="android.permission.WRITE_SETTINGS" />
    
  • 确保已禁用

    Settings.System.putInt(
        getContentResolver(),
        Settings.System.ACCELEROMETER_ROTATION,
        0
    );
    
  • 设置为所需设置,该设置应为以下选项之一。这些值表示屏幕相对于设备自然方向的旋转,可以是横向或纵向

    Settings.System.putInt(
        getContentResolver(),
        Settings.System.USER_ROTATION,
        Surface.ROTATION_0 //Or a different ROTATION_ constant
    );
    
  • 请注意,即使您的应用未运行或已卸载,更改也会持续存在。如果调用正确,用户可以通过手动禁用和启用自动旋转来重置此值。

    创建系统视图 创建始终显示在其他应用程序顶部的不可见窗口。可以指定自己的方向首选项,因此可以使用视图的方向来替代基础视图和应用程序的方向

    选择权 我知道可以使用几种不同的视图类型来实现这一点,每种视图类型都有各自的缺点

  • 系统覆盖窗口()

    需要许可。(将以下内容添加到。)

    用法 缺点
    • 根据我的经验,如果你的应用程序崩溃或被杀死,这个视图可能会一直存在。重启设备似乎可以解决这个问题
    工具书类
    • 窗口类型和z顺序之间的映射:
    • 每种窗口类型所需的权限:

    这似乎是最终用户的问题,而不是编程问题。答案是不能全局设置方向。任何应用程序都可以选择自行处理方向,如果这样做,则可以选择忽略对设备方向的更改,或者根据自己的标准更改方向。有些应用甚至无法在景观模式(或纵向模式)下正确显示,因此即使可能,也不希望覆盖它们选择的方向。你可以。您创建一个隐藏的系统对话框,并在其上设置某些标志,并请求横向定位。当我确信它能工作时,我会发布整个源代码。@Ahmad,这似乎只是禁用了系统自动旋转,它不会直接让你控制屏幕方向。我试过你的应用程序,发现它工作正常。但是,这个答案中的代码对我不起作用。它不会改变屏幕方向,当我转到主屏幕时,图标和文本不可见。您是否最终更改了此算法以使其在您的应用程序中正常工作?进一步调查发现,您的上述代码在从服务运行时运行正常,但在从活动运行时运行正常。也许这与所使用的上下文有关。(我不擅长安卓,所以我不知道。)@Sam嘿,谢谢你的提示!从服务台打电话就成功了!第3点中的代码应该写在哪里?此外,您的代码片段是强制所有应用程序定向,还是仅强制其写入的应用程序定向?@Basher51,最好在第4点中的代码之前运行它。当启用Android自动旋转时,第4点中的代码似乎没有任何效果,这就是为什么第3点是必要的。@Basher51,它似乎会影响所有应用程序(这就是我所说的全局应用程序),除了指定自己方向首选项的应用程序之外,所以它不会真正强制方向。嘿,我尝试了你的代码片段,并在没有任何运气的情况下修改了几次。您是否从服务执行该代码才能工作?谢谢是的,我想是的。当我选择
    windowType=LayoutParams.TYPE\u APPLICATION\u OVERLAY
    :)
    Settings.System.putInt(
        getContentResolver(),
        Settings.System.USER_ROTATION,
        Surface.ROTATION_0 //Or a different ROTATION_ constant
    );
    
    <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
    
    public class ScreenOrientationEnforcer {
    
        private final View view;
        private final WindowManager windows;
    
        public ScreenOrientationEnforcer(Context context) {
            windows = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
            view = new View(context);
        }
    
        public void start() {
            WindowManager.LayoutParams layout = generateLayout();
            windows.addView(view, layout);
            view.setVisibility(View.VISIBLE);
        }
    
        public void stop() {
            windows.removeView(view);
        }
    
        private WindowManager.LayoutParams generateLayout() {
            WindowManager.LayoutParams layoutParams = new WindowManager.LayoutParams();
    
            //So we don't need a permission or activity
            //Note that this won't work on some devices running MIUI
            layoutParams.type = WindowManager.LayoutParams.TYPE_TOAST;
    
            //Just in case the window type somehow doesn't enforce this
            layoutParams.flags =
                WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
                | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
    
            //Prevents breaking apps that detect overlying windows enabling
            //(eg UBank app, or enabling an accessibility service)
            layoutParams.width = 0;
            layoutParams.height = 0;
    
            //Try to make it completely invisible
            layoutParams.format = PixelFormat.TRANSPARENT;
            layoutParams.alpha = 0f;
    
            //The orientation to force
            layoutParams.screenOrientation = ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
    
            return layoutParams;
        }
    
    }
    
    ScreenOrientationEnforcer screenOrientationEnforcer
        = new ScreenOrientationEnforcer(context);
    
    //Force screen orientation
    screenOrientationEnforcer.start();
    
    //Stop forcing screen orientation
    screenOrientationEnforcer.stop();