17

我正在开发一个锁屏应用程序,我需要禁用下拉屏幕顶部的通知/状态栏的功能。有一个名为 Holo Locker 的应用程序,该应用程序的作用是当用户从屏幕顶部向下拉时,它只是将栏重新设置到屏幕顶部,并且无法将抽屉拉下。

我不知道从哪里开始。任何帮助都会很棒!谢谢!

4

6 回答 6

32

这可以使用反射来实现。不过也有很多问题。

无法检查通知面板是否打开或打开。因此,我们将不得不依赖Activity#onWindowFocusChanged(boolean). 这就是问题开始的地方。

该方法的作用:

public void onWindowFocusChanged (boolean hasFocus)

当活动的当前窗口获得或失去焦点时调用。这是该活动是否对用户可见的最佳指标。

因此,我们必须找出一种方法来区分由于显示通知面板而导致的焦点丢失和由于其他事件导致的焦点丢失。

一些将触发的事件onWindowFocusChanged(boolean)

  • 将活动发送到后台(用户切换应用程序或按下home按钮)时,窗口焦点会丢失

  • 由于 Dialogs 和 PopupWindows 在各自独立的窗口中打开,因此在显示这些窗口时 Activity 的窗口焦点将丢失。

  • Activity 的窗口失去焦点的另一个实例是单击微调器时,会显示一个 PopupWindow。

您的活动可能不必处理所有这些问题。以下示例处理其中的一个子集:

首先,您需要以下EXPAND_STATUS_BAR权限:

<uses-permission android:name="android.permission.EXPAND_STATUS_BAR" />

接下来,在您的活动中声明这些类范围变量:

// To keep track of activity's window focus
boolean currentFocus;

// To keep track of activity's foreground/background status
boolean isPaused;

Handler collapseNotificationHandler;

覆盖onWindowFocusChanged(boolean)

@Override
public void onWindowFocusChanged(boolean hasFocus) {

    currentFocus = hasFocus;

    if (!hasFocus) {

        // Method that handles loss of window focus
        collapseNow();
    }
}

定义collapseNow()

public void collapseNow() {

    // Initialize 'collapseNotificationHandler'
    if (collapseNotificationHandler == null) {
        collapseNotificationHandler = new Handler();
    }

    // If window focus has been lost && activity is not in a paused state
    // Its a valid check because showing of notification panel
    // steals the focus from current activity's window, but does not 
    // 'pause' the activity
    if (!currentFocus && !isPaused) {

        // Post a Runnable with some delay - currently set to 300 ms
        collapseNotificationHandler.postDelayed(new Runnable() {

            @Override
            public void run() {

                // Use reflection to trigger a method from 'StatusBarManager'                

                Object statusBarService = getSystemService("statusbar");
                Class<?> statusBarManager = null;

                try {
                    statusBarManager = Class.forName("android.app.StatusBarManager");
                } catch (ClassNotFoundException e) {
                    e.printStackTrace();
                }

                Method collapseStatusBar = null;

                try {

                    // Prior to API 17, the method to call is 'collapse()'
                    // API 17 onwards, the method to call is `collapsePanels()`

                    if (Build.VERSION.SDK_INT > 16) {
                        collapseStatusBar = statusBarManager .getMethod("collapsePanels");
                    } else {
                        collapseStatusBar = statusBarManager .getMethod("collapse");
                    }
                } catch (NoSuchMethodException e) {
                    e.printStackTrace();
                }

                collapseStatusBar.setAccessible(true);

                try {
                    collapseStatusBar.invoke(statusBarService);
                } catch (IllegalArgumentException e) {
                    e.printStackTrace();
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                } catch (InvocationTargetException e) {
                    e.printStackTrace();
                }

                // Check if the window focus has been returned
                // If it hasn't been returned, post this Runnable again
                // Currently, the delay is 100 ms. You can change this
                // value to suit your needs.
                if (!currentFocus && !isPaused) {
                    collapseNotificationHandler.postDelayed(this, 100L);
                }

            }
        }, 300L);
    }   
}

处理活动的onPause()onResume()

@Override
protected void onPause() {
    super.onPause();

    // Activity's been paused      
    isPaused = true;
}

@Override
protected void onResume() {
    super.onResume();

    // Activity's been resumed
    isPaused = false;
}

希望这与您正在寻找的内容接近。

注意:不幸的是,当您滑动通知栏并按住它时发生的闪烁是不可避免的。但是,可以使用处理程序延迟的“更好”值来控制/改进其外观。Holo Locker 应用程序中也存在此问题。

于 2013-11-15T19:12:50.983 回答
9

如果您只想阻止用户打开状态,请尝试以下操作:

getWindow().addFlags(WindowManager.LayoutParams.[TYPE_SYSTEM_OVERLAY][1]);

用法 :

super.onCreate(savedInstanceState);
getWindow().addFlags(WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY);
setContentView(R.layout.your_layout);

之前添加 根据您的具体需要,您可以选择合适的WindowManager.LayoutParams

希望这可以帮助。

于 2015-09-04T07:34:55.683 回答
8
        private void disablePullNotificationTouch() {
                WindowManager manager = ((WindowManager) getApplicationContext()
                        .getSystemService(Context.WINDOW_SERVICE));
                WindowManager.LayoutParams localLayoutParams = new WindowManager.LayoutParams();
                localLayoutParams.type = WindowManager.LayoutParams.TYPE_SYSTEM_ERROR;
                localLayoutParams.gravity = Gravity.TOP;
                localLayoutParams.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE |

                        // this is to enable the notification to recieve touch events
                        WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL |

                        // Draws over status bar
                        WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;

                localLayoutParams.width = WindowManager.LayoutParams.MATCH_PARENT;
                localLayoutParams.height = (int) (25 * getResources()
                        .getDisplayMetrics().scaledDensity);
                localLayoutParams.format = PixelFormat.RGBX_8888;
                customViewGroup view = new customViewGroup(this);
                manager.addView(view, localLayoutParams);
            }

    //Add this class in your project
    public class customViewGroup extends ViewGroup {

        public customViewGroup(Context context) {
            super(context);
        }

        @Override
        protected void onLayout(boolean changed, int l, int t, int r, int b) {
        }

        @Override
        public boolean onInterceptTouchEvent(MotionEvent ev) {

            Log.v("customViewGroup", "**********Intercepted");
            return true;
        }
于 2016-03-22T09:54:55.397 回答
2

我尝试了接受的答案,但我仍然能够下拉并快速更改一些设置。

一个不同的解决方案可以防止用户完全拉下菜单,我更喜欢这里接受的答案。

于 2014-09-22T09:59:48.373 回答
0
WindowManager manager = ((WindowManager) getApplicationContext().getSystemService(Context.WINDOW_SERVICE));

WindowManager.LayoutParams localLayoutParams = new WindowManager.LayoutParams();
localLayoutParams.type = WindowManager.LayoutParams.TYPE_SYSTEM_ERROR;
localLayoutParams.gravity = Gravity.TOP;
localLayoutParams.flags = 
    WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE |

    // this is to enable the notification to receive touch events
    WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL |

    // Draws over status bar
    WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;

localLayoutParams.width = WindowManager.LayoutParams.MATCH_PARENT;
localLayoutParams.height = (int) (40 * getResources().getDisplayMetrics().scaledDensity);
localLayoutParams.format = PixelFormat.TRANSPARENT;

blockingView = new CustomViewGroup(this);
manager.addView(blockingView, localLayoutParams);

使用这个并参考 Class customViewGroup的链接

于 2018-04-13T10:50:20.640 回答
-3

这听起来绝对是个好主意。您将破坏用户期望存在的默认操作系统功能。幸运的是,我认为这是不可能的,但你可以实现类似的东西,使你的活动全屏。

public class FullScreen extends Activity {
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        requestWindowFeature(Window.FEATURE_NO_TITLE);
        getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, 
                                WindowManager.LayoutParams.FLAG_FULLSCREEN);

        setContentView(R.layout.main);
    }
}

如果您找到比这更好的解决方案,请告诉我,我很想知道。

谢谢你。

于 2013-11-15T07:29:32.797 回答