web-dev-qa-db-fra.com

Empêcher l'extension de la barre d'état

Existe-t-il de toute façon pour empêcher les utilisateurs de faire glisser la barre d'état (développer) ou de se replier?

J'essaie un remplacement d'écran de verrouillage et semble que c'est une fonctionnalité incontournable. Existe-t-il un moyen possible de le faire sans avoir besoin des privilèges root?

21
Ye Myat Min

Vous pouvez réellement empêcher la barre d'état de s'étendre, sans rooter le téléphone. Voir ce lien . Cela dessine une fenêtre à la hauteur de la barre d'état et consomme tous les événements tactiles.

Appelez le code suivant juste après onCreate ().

public static void preventStatusBarExpansion(Context context) {
    WindowManager manager = ((WindowManager) context.getApplicationContext()
            .getSystemService(Context.WINDOW_SERVICE));

    Activity activity = (Activity)context;
    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;
    //https://stackoverflow.com/questions/1016896/get-screen-dimensions-in-pixels
    int resId = activity.getResources().getIdentifier("status_bar_height", "dimen", "Android");
    int result = 0;
    if (resId > 0) {
        result = activity.getResources().getDimensionPixelSize(resId);
    }

    localLayoutParams.height = result;

    localLayoutParams.format = PixelFormat.TRANSPARENT;

    customViewGroup view = new customViewGroup(context);

    manager.addView(view, localLayoutParams);
}

public static 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;
    }
}
18
Kristy Welsh

Réponse courte: c'est impossible!

Maintenant, si vous êtes intéressé de savoir pourquoi cela est impossible:

Il existe deux autorisations pour manipuler la barre d'état du système, EXPAND_STATUS_BAR et STATUS_BAR . La première peut être demandée par n'importe quelle application, mais la dernière est réservée aux applications signées avec la signature de la plateforme (applications système, pas tierces). Il est possible d'agrandir/réduire la barre d'état du système (voir "Comment ouvrir ou étendre la barre d'état par intention?" ) mais notez que la réflexion est requise car la classe StatusBarManager ne fait pas partie du SDK. La méthode de désactivation, utilisée par le numéroteur Android pour empêcher l'extension de la barre d'état), n'est pas accessible par une application sans l'autorisation STATUS_BAR susmentionnée.

Sources: expérience personnelle :-)

17
Tom

Tout d'abord, il est impossible de modifier la barre d'état si votre application n'est pas signée avec la certification rom du téléphone, si vous essayez de la modifier, vous obtiendrez une exception de sécurité.

pdate: Dans les nouvelles API, la méthode est "collapsePanels" au lieu de "collapse".

La seule façon que j'ai trouvée après plusieurs heures de travail est de remplacer la méthode "onWindowFocusChanged" de l'activité et quand elle perd le focus (peut-être que l'utilisateur a touché la barre des notifications), forcez à réduire la barre d'état, voici le code (travail sur un Defy + 2.3.5).

Vous devez déclarer l'autorisation suivante sur le manifeste:

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

Et remplacez la méthode suivante:

public void onWindowFocusChanged(boolean hasFocus)
{
        try
        {
           if(!hasFocus)
           {
                Object service  = getSystemService("statusbar");
                Class<?> statusbarManager = Class.forName("Android.app.StatusBarManager");
                Method collapse = statusbarManager.getMethod("collapse");
                collapse .setAccessible(true);
                collapse .invoke(service);
           }
        }
        catch(Exception ex)
        {
        }
}

pdate: Vous devrez utiliser votre propre boîte de dialogue d'alerte personnalisée en la remplaçant également par sa méthode onWindowFocusChanged, car les boîtes de dialogue d'alerte ont leur propre focus.

15
PoOk

En fait, cela peut être fait via un petit hack que j'ai découvert accidentellement, mais nécessite l'autorisation Android.permission.SYSTEM_ALERT_WINDOW:

Ce que vous faites est d'ajouter une vue de la taille exacte de la barre d'état directement au WindowManager avec certains paramètres qui couvrent la barre d'état et l'empêchent de recevoir des événements tactiles:

View disableStatusBarView = new View(context);

WindowManager.LayoutParams handleParams = new WindowManager.LayoutParams(
    WindowManager.LayoutParams.FILL_PARENT,
    <height of the status bar>,
    // This allows the view to be displayed over the status bar
    WindowManager.LayoutParams.TYPE_SYSTEM_ALERT,
    // this is to keep button presses going to the background window
    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,
    PixelFormat.TRANSLUCENT);

handleParams.gravity = Gravity.TOP;
context.getWindow().addView(disableStatusBarView, handleParams);

Cela créera essentiellement une vue transparente sur la barre d'état qui recevra tous les événements tactiles et empêchera les événements d'atteindre la barre d'état et empêchera donc son expansion.

REMARQUE: ce code n'est pas testé, mais le concept fonctionne.

13
Grantland Chew

J'ai essayé les solutions mentionnées par GrantLand et PoOk mais les deux n'ont pas fonctionné dans mon cas. Cependant, une autre solution Effacer/Masquer la liste des tâches récentes a fait l'affaire pour moi. J'écris une application de lancement pour laquelle j'ai dû désactiver un menu d'applications récentes afin que l'utilisateur ne puisse pas en ouvrir une application verrouillée. De plus, je devais empêcher l'expansion de la barre de notification et cette astuce m'a permis d'atteindre les deux. Remplacez la méthode OnWindowFocusChanged dans votre activité et vérifiez si c'est ce que vous vouliez.

public void onWindowFocusChanged(boolean hasFocus) {
    super.onWindowFocusChanged(hasFocus);

        Log.d("Focus debug", "Focus changed !");

    if(!hasFocus) {
        Log.d("Focus debug", "Lost focus !");

        Intent closeDialog = new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
        sendBroadcast(closeDialog);
    }
}
8
Abdul Rehman

Pour un écran de verrouillage Pourquoi n'utilisez-vous pas simplement les éléments suivants dans votre activité principale:

@Override
public void onAttachedToWindow() {
        getWindow().addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED);
        getWindow().addFlags(WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD);
}

Si l'utilisateur ne dispose pas d'un écran de verrouillage sécurisé, l'application permet à l'utilisateur de tirer la barre d'état vers le bas et d'ouvrir des activités, mais cela n'a pas d'importance car, de toute évidence, l'utilisateur ne veut pas d'écran sécurisé.

Si l'utilisateur a un écran de verrouillage sécurisé, l'application affichera la barre d'état mais ne permettra pas d'interaction avec elle. En effet, le téléphone est toujours verrouillé et seule votre activité est autorisée à fonctionner jusqu'à ce que l'utilisateur déverrouille le téléphone. De plus, la fermeture de votre application ouvrira également l'écran de verrouillage sécurisé standard. Tout cela est hautement souhaitable car vous n'avez pas à passer tout ce temps à coder des fonctionnalités sécurisées que vous ne pouvez pas garantir seront aussi sécurisées que celles en stock.

Si vous ne voulez vraiment pas que l'utilisateur puisse interagir avec la barre d'état, vous pouvez peut-être laisser le drapeau FLAG_DISMISS_KEYGUARD appel. Puis juste avant de déverrouiller le téléphone, placez le drapeau comme je l'ai montré dans le premier bloc. Je ne sais pas si cette dernière partie fonctionne mais ça vaut le coup d'essayer.

J'espère que cela pourra aider

3
Kyle O.

Désolé mais cela ne fonctionne pas. en utilisant FLAG_LAYOUT_IN_SCREEN vous empêche d'attraper des événements tactiles.

Et BTW: pour ajouter une vue à la fenêtre, utilisez le gestionnaire de fenêtres:

WindowManager winMgr = (WindowManager)getSystemService(WINDOW_SERVICE);
winMgr.addView(disableStatusBar, handleParams); 
1
Gil SH