zoukankan      html  css  js  c++  java
  • 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的功能,不需要修改。

  • 相关阅读:
    背水一战 Windows 10 (26)
    背水一战 Windows 10 (25)
    背水一战 Windows 10 (24)
    背水一战 Windows 10 (23)
    背水一战 Windows 10 (22)
    背水一战 Windows 10 (21)
    背水一战 Windows 10 (20)
    背水一战 Windows 10 (19)
    背水一战 Windows 10 (18)
    背水一战 Windows 10 (17)
  • 原文地址:https://www.cnblogs.com/kunkka/p/10778702.html
Copyright © 2011-2022 走看看