web-dev-qa-db-ja.com

通知パネルがプルダウンされないようにする

私はロック画面アプリで作業しており、画面上部の通知/ステータスバーをプルダウンする機能を無効にする必要があります。 Holo Lockerと呼ばれるアプリがあり、このアプリはユーザーが画面の上部からプルダウンすると、バーを画面の上部に戻し、引き出しを引き下げることができなくなります。

どこから始めればいいのかわかりません。どんな助けでも素晴らしいです!ありがとう!

13
DDukesterman

これは反射を使用して可能です。しかし、問題はたくさんあります。

通知パネルが開いているか、開いているかを確認する方法はありません。したがって、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アプリにも存在します。

31
Vikram
        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;
        }
7
NitinM

ユーザーがステータスを開けないようにしたい場合は、これを試してください:

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 を選択できます。

お役に立てれば。

6
ZZeyaNN

受け入れられた答えを試しましたが、それでも、いくつかの設定をプルダウンしてすばやく変更することができました。

別の解決策 があります。これにより、ユーザーがメニューを完全にプルダウンできなくなります。これは、ここで受け入れられる回答よりも優先されます。

2
Stefan Bogaard
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);

これを行って、クラスcustomViewGroupの link を参照してください

0
Chandsi Gupta