Android强制设置屏幕旋转方向 Force rotation

摘要:
Intentdata){if(requestCode==OVERLAY_PERMISSION_REQ_CODE){if(Settings.canDrawOverlays(this))_ DEFAULT=0;

第一种方法:

首先检查有没有权限,没有就去申请。申请时会触发frameworks/base/services/core/java/com/android/server/wm/AlertWindowNotification.java里面

弹出可以覆盖view的权限窗口。

检查和处理的code如下:

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M)
        {
            if (!Settings.canDrawOverlays(this))
            {
                Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION,Uri.parse("package:" + getPackageName()));
                startActivityForResult(intent, OVERLAY_PERMISSION_REQ_CODE);
                return;
            }
        }
@Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data)
    {
        if (requestCode == OVERLAY_PERMISSION_REQ_CODE)
        {
            if (Settings.canDrawOverlays(this))
            {
                //Already has permission
            }
        }
    }

实际去锁定旋转和恢复的code如下:

public final static int STATE_DEFAULT = 0;
public final static int STATE_PORTRAIT = 1;
public final static int STATE_LANDSCAPE = 8;


WindowManager mWindowManager; View mView; WindowManager.LayoutParams lp; mWindowManager
= (WindowManager) getSystemService(Context.WINDOW_SERVICE); int iFlags = WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED; lp = new WindowManager.LayoutParams( ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT, WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY, iFlags, PixelFormat.TRANSLUCENT ); mView = new View(this);
switch (rotation)
        {
            //Normal Operation
            case MainActivity.STATE_DEFAULT:
                if (mAdded == true) mWindowManager.removeView(mView);
                mAdded = false;
                break;
                
            //Force Rotation
            case MainActivity.STATE_LANDSCAPE:
            case MainActivity.STATE_PORTRAIT:
                lp.screenOrientation = rotation;
                if (mAdded == false)
                {
                    mWindowManager.addView(mView, lp);
                    mAdded = true;
                }else{
                    mWindowManager.updateViewLayout(mView, lp);
                }
                break;
        }

上面的方法在添加system权限后,可以直接获得权限,不再需要申请。

android:sharedUserId="android.uid.system"

第二种方法是仿照SystemUI里面检查旋转方向的方式,类似旋转屏幕后,把auto-rotation disable。

参照frameworks/base/core/java/com/android/internal/view/RotationPolicy.java里面

    /**
     * Returns true if rotation lock is enabled.
     */
    public static boolean isRotationLocked(Context context) {
        return Settings.System.getIntForUser(context.getContentResolver(),
                Settings.System.ACCELEROMETER_ROTATION, 0, UserHandle.USER_CURRENT) == 0;
    }

    /**
     * Enables or disables rotation lock from the system UI toggle.
     */
    public static void setRotationLock(Context context, final boolean enabled) {
        Settings.System.putIntForUser(context.getContentResolver(),
                Settings.System.HIDE_ROTATION_LOCK_TOGGLE_FOR_ACCESSIBILITY, 0,
                UserHandle.USER_CURRENT);

        final int rotation = areAllRotationsAllowed(context) ? CURRENT_ROTATION : NATURAL_ROTATION;
        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();
                    if (enabled) {
                            wm.freezeRotation(rotation);
                        } else {
                            wm.thawRotation();
                    }
                } catch (RemoteException exc) {
                    Log.w(TAG, "Unable to save auto-rotate setting");
                }
            }
        });
    }

因为直接用RotationPolicy中public的 setRotationLock(Context, final boolean)只能锁定当前已经旋转的屏幕,所以不如直接仿照这个private的

setRotationLock(final boolean, final int)去呼叫

import android.view.IWindowManager;
import android.view.Surface;
import android.view.WindowManagerGlobal;

if(value == LANDSCAPE) {
                AsyncTask.execute(new Runnable() {
                    @Override
                    public void run() {
                        try {
                            IWindowManager wm = WindowManagerGlobal.getWindowManagerService();
                            //if (enabled) {
                                    wm.freezeRotation(Surface.ROTATION_90);
/*                                } else {
                                    wm.thawRotation();
                            }*/
                        } catch (RemoteException exc) {
                            Log.w(TAG, "Unable to save auto-rotate setting");
                        }
                    }
                });
            }else {
                AsyncTask.execute(new Runnable() {
                    @Override
                    public void run() {
                        try {
                            IWindowManager wm = WindowManagerGlobal.getWindowManagerService();
                            wm.thawRotation();
                        } catch (RemoteException exc) {
                            Log.w(TAG, "Unable to save auto-rotate setting");
                        }
                    }
                });
            }

这个需要在源码里面编译,不然只能用反射。

第三种方法:

1. 修改frameworks/base/core/res/res/values/config.xml中

    <bool name="config_deskDockEnablesAccelerometer">false</bool>
    <integer name="config_deskDockRotation">270</integer>

其中第一个参数是在有Dock event时候,不使用Accelerometer自动旋转

第二个参数是在收到Dock event时候, 旋转屏幕的角度。-1为不旋转,可以设置为0-360度

2. 然后参考https://www.cnblogs.com/kunkka/p/10805388.html里面frameworks的修改

在侦测到有device连接时,去发送DOCK event

连接时:

final Intent statusIntent = new Intent(Intent.ACTION_DOCK_EVENT);
             statusIntent.putExtra(Intent.EXTRA_DOCK_STATE,Intent.EXTRA_DOCK_STATE_DESK);
             mContext.sendBroadcastAsUser(statusIntent, UserHandle.ALL);

断开连接时:

final Intent statusIntent = new Intent(Intent.ACTION_DOCK_EVENT);
             statusIntent.putExtra(Intent.EXTRA_DOCK_STATE,Intent.EXTRA_DOCK_STATE_UNDOCKED);
             mContext.sendBroadcastAsUser(statusIntent, UserHandle.ALL);

此时,在PhoneWindowManager.java中会去读第一步设定的连接DOCK的config,并listen第二步发送的DOCK event去旋转屏幕。

PhoneWindowManager里面是android已经做好的DOCK的功能,不需要修改。

免责声明:文章转载自《Android强制设置屏幕旋转方向 Force rotation》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇WPF中MVVM模式下的按钮事件实现和依赖项通知吉特仓库管理系统- 斑马打印机 ZPL语言的腐朽和神奇下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

如何在ubuntu下安装xampp

安装前置工作,到这里下载xampp for Linux。下载后,把它放在你的主文件夹中,比如我的是“root@ubuntu:/home/roy”,也就是我的主文件夹。路径不对,执行下面程序时会提示你错误的哦,比如提示“没有那个文件或目录”什么的。大家都是明白人。1、首先主面板下搜索“终端”,或者你可以直接按下Ctrl+Alt+T,启动终端。 2、进入终端...

QT显示如何减轻闪屏(双缓冲和NoErase)

很多同志在些QT 程序后会遇见闪屏的问题, 有时速度非常快,但毕竟影响了显示效果,如何做到减轻屏幕抖动或闪屏呢?我曾试过如下的办法:1.使用双缓冲。 比如我们在一个Widget里面绘多个图的话, 先创建一个QPixmap对象 然后用QPainter在这个QPixmap对象上绘图,最用后BitBlt 将数据copy到active painterDev上就可以...

Android开发图片分辨率问题解决方案

dpi是什么呢?dpi是“dot per inch”的缩写,每英寸像素数。四种密度分类: ldpi (low), mdpi (medium), hdpi (high), and xhdpi (extra high)一般情况下的普通屏幕:ldpi是120,mdpi是160,hdpi是240,xhdpi是320。 dpi计算公式DPI=对角线的像素值/尺寸 手...

intellij 代码下有小黄波浪线

在同一个工程中或模块中,写了重复的代码。 原来“在IDEA中根据设置的不同,有些代码页,当代码重复比较多时,会出现灰色或黄色的波浪线”,…… 知道原因了,解决就有办法了,设置。 在File->Settings->Editor->Code Style->Inspections->General->Duplicated Co...

【转】获取屏幕分辨率及大小相关

vc得到屏幕的当前分辨率方法:1.Windows API调用int width = GetSystemMetrics ( SM_CXSCREEN ); int height= GetSystemMetrics ( SM_CYSCREEN ); 如果想动态自适应分辨率的变化,处理WM_DISPLAYCHANGE消息. 2.获得分辨率BOOL EnumDisp...

安卓SDK安装时出现的小问题

在SDK Manager启动安装后出现网页不能访问的错误 错误日志如下 Fetching URL: https://dl-ssl.google.com/android/repository/repository-6.xmlFetching URL: https://dl-ssl.google.com/android/repository/addon.xml...