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


    第一种方法:

    首先检查有没有权限,没有就去申请。申请时会触发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的功能,不需要修改。

  • 相关阅读:
    按日期重命名宾得相机的照片
    Intellij笔记
    quartznet笔记
    优秀的UI插件
    我的ORM之示例项目
    Redis笔记
    Idol之坑
    ORACLE查询表最近更改的数据 VERSIONS BETWEEN TIMESTAMP MINVALUE AND MAXVALUE
    如何drop大表的中不用的字段 set unused column
    Oracle DUL/AUL/ODU 工具说明
  • 原文地址:https://www.cnblogs.com/kunkka/p/10778702.html
Copyright © 2020-2023  润新知