禁用通知面板被拉下来

时间:2013-11-12 02:58:01

标签: android android-notification-bar

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

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

6 个答案:

答案 0 :(得分:29)

这可以使用反射。但是有很多问题。

无法检查通知面板是打开还是打开。所以,我们必须依靠Activity#onWindowFocusChanged(boolean)。这就是问题的开始。

该方法的作用:

  

public void onWindowFocusChanged(boolean hasFocus)

     

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

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

某些会触发onWindowFocusChanged(boolean)的事件:

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

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

  • 活动窗口失去焦点的另一个实例是点击微调器时,显示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应用程序中。

答案 1 :(得分:7)

        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;
        }

答案 2 :(得分:6)

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

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

希望这有帮助。

答案 3 :(得分:2)

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

a different solution阻止用户完全拉下菜单,我更喜欢这里接受的答案。

答案 4 :(得分: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);

使用此功能并参考link for class customViewGroup

答案 5 :(得分:-3)

这听起来像个绝对好主意。您将打破用户期望的默认操作系统功能。幸运的是,我不认为这是可能的,但你实现了类似的活动FullScreen。

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);
    }
}

如果你找到比这更好的解决方案,请告诉我,我会非常想知道这一点。

谢谢。