我正在开发一个锁屏应用程序,我需要禁用在屏幕顶部拉下通知/状态栏的功能。有一个叫做Holo Locker的应用程序,这个应用程序的作用是当用户从屏幕顶部向下拉时,它只是将酒吧设置回屏幕顶部,使其无法向下拉抽屉。我不知道从何说起。任何帮助将是伟大的!谢谢!
xhv8bpkk1#
这可以使用反射。但也有很多问题。没有办法检查通知面板是否打开或正在打开。因此,我们必须依赖Activity#onWindowFocusChanged(boolean)。这就是问题的开始。该方法的作用:public void onWindowFocusChanged(boolean hasFocus)当Activity的当前Window获得或失去焦点时调用。这是此活动是否对用户可见的最佳指示器。因此,我们必须找出一种方法来区分由于显示通知面板而导致的焦点丢失和由于其他事件而导致的焦点丢失。一些会触发onWindowFocusChanged(boolean)的事件:
Activity#onWindowFocusChanged(boolean)
onWindowFocusChanged(boolean)
home
您的活动可能不必处理所有这些问题。下面的示例处理其中的一个子集:首先,您需要EXPAND_STATUS_BAR权限:
EXPAND_STATUS_BAR
<uses-permission android:name="android.permission.EXPAND_STATUS_BAR" />
接下来,在Activity中声明这些类作用域变量:
// To keep track of activity's window focusboolean currentFocus;// To keep track of activity's foreground/background statusboolean isPaused;Handler collapseNotificationHandler;
// 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):
@Overridepublic void onWindowFocusChanged(boolean hasFocus) { currentFocus = hasFocus; if (!hasFocus) { // Method that handles loss of window focus collapseNow(); }}
@Override
public void onWindowFocusChanged(boolean hasFocus) {
currentFocus = hasFocus;
if (!hasFocus) {
// Method that handles loss of window focus
collapseNow();
}
定义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); } }
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() {
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;
// 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) {
collapseStatusBar.setAccessible(true);
collapseStatusBar.invoke(statusBarService);
} catch (IllegalArgumentException e) {
} catch (IllegalAccessException e) {
} catch (InvocationTargetException e) {
// 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.
collapseNotificationHandler.postDelayed(this, 100L);
}, 300L);
处理Activity的onPause()和onResume():
onPause()
onResume()
@Overrideprotected void onPause() { super.onPause(); // Activity's been paused isPaused = true;}@Overrideprotected void onResume() { super.onResume(); // Activity's been resumed isPaused = false;}
protected void onPause() {
super.onPause();
// Activity's been paused
isPaused = true;
protected void onResume() {
super.onResume();
// Activity's been resumed
isPaused = false;
希望这是接近你正在寻找的。注意:当您滑动通知栏并按住它时发生的 Flink 是不可避免的。然而,其外观可以使用处理器延迟的“更好”值来控制/改进。这个问题也存在于Holo Locker应用程序中。
mepcadol2#
如果您只是想阻止用户打开状态,请尝试以下操作:
getWindow().addFlags(WindowManager.LayoutParams.[TYPE_SYSTEM_OVERLAY][1]);
用途:
super.onCreate(savedInstanceState);getWindow().addFlags(WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY);setContentView(R.layout.your_layout);
super.onCreate(savedInstanceState);
getWindow().addFlags(WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY);
setContentView(R.layout.your_layout);
根据您的具体需要,您可以选择适当的WindowManager.LayoutParams。希望这能帮上忙。
cunj1qz13#
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; }
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);
protected void onLayout(boolean changed, int l, int t, int r, int b) {
public boolean onInterceptTouchEvent(MotionEvent ev) {
Log.v("customViewGroup", "**********Intercepted");
return true;
jgzswidk4#
我尝试了接受的答案,但我仍然能够拉下来,并迅速改变一些设置。有一个不同的解决方案,防止用户完全拉下菜单,我更喜欢这里接受的答案。
mwecs4sa5#
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);
WindowManager manager = ((WindowManager) getApplicationContext().getSystemService(Context.WINDOW_SERVICE));
localLayoutParams.flags =
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE |
// this is to enable the notification to receive touch events
localLayoutParams.height = (int) (40 * getResources().getDisplayMetrics().scaledDensity);
localLayoutParams.format = PixelFormat.TRANSPARENT;
blockingView = new CustomViewGroup(this);
manager.addView(blockingView, localLayoutParams);
使用此命令并引用link以获得类customViewGroup
xmakbtuz6#
听起来是个好主意。你会破坏用户期望的默认操作系统功能。幸运的是,我不认为这是可能的,但你实现了类似的东西,使您的活动全屏。
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); }}
public class FullScreen extends Activity {
public void onCreate(Bundle savedInstanceState) {
requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
setContentView(R.layout.main);
如果你找到比这更好的解决办法,一定要让我知道,我会渴望知道的。谢谢你。
6条答案
按热度按时间xhv8bpkk1#
这可以使用反射。但也有很多问题。
没有办法检查通知面板是否打开或正在打开。因此,我们必须依赖
Activity#onWindowFocusChanged(boolean)
。这就是问题的开始。该方法的作用:
public void onWindowFocusChanged(boolean hasFocus)
当Activity的当前Window获得或失去焦点时调用。这是此活动是否对用户可见的最佳指示器。
因此,我们必须找出一种方法来区分由于显示通知面板而导致的焦点丢失和由于其他事件而导致的焦点丢失。
一些会触发
onWindowFocusChanged(boolean)
的事件:home
按钮)时,窗口焦点丢失您的活动可能不必处理所有这些问题。下面的示例处理其中的一个子集:
首先,您需要
EXPAND_STATUS_BAR
权限:接下来,在Activity中声明这些类作用域变量:
覆盖
onWindowFocusChanged(boolean)
:定义
collapseNow()
:处理Activity的
onPause()
和onResume()
:希望这是接近你正在寻找的。
注意:当您滑动通知栏并按住它时发生的 Flink 是不可避免的。然而,其外观可以使用处理器延迟的“更好”值来控制/改进。这个问题也存在于Holo Locker应用程序中。
mepcadol2#
如果您只是想阻止用户打开状态,请尝试以下操作:
用途:
根据您的具体需要,您可以选择适当的WindowManager.LayoutParams。
希望这能帮上忙。
cunj1qz13#
jgzswidk4#
我尝试了接受的答案,但我仍然能够拉下来,并迅速改变一些设置。
有一个不同的解决方案,防止用户完全拉下菜单,我更喜欢这里接受的答案。
mwecs4sa5#
使用此命令并引用link以获得类customViewGroup
xmakbtuz6#
听起来是个好主意。你会破坏用户期望的默认操作系统功能。幸运的是,我不认为这是可能的,但你实现了类似的东西,使您的活动全屏。
如果你找到比这更好的解决办法,一定要让我知道,我会渴望知道的。
谢谢你。