Android5.0禁止状态栏下拉

本文亲测有效,如有疑问,请在下方留言。

禁止锁屏下拉分两种情况,一种是像我这样可以修改系统源码的,一种是在上面开发的第三方app的(没有系统权限)。两种方式的处理不一样;
再说具体怎么实现前我们先探索一下源码(不感兴趣可以直接跳过);

有先时候有需求需要屏蔽状态栏下拉,例如com.android.phone中的紧急呼叫时(sim卡锁住),此时源码设计是状态栏下拉不了的。
Android中有许多隐藏的Service,StatusBarManager就是其中一个,在Context.java中可以看到:

/** 
 * Use with {@link #getSystemService} to retrieve a {@link 
 * android.app.StatusBarManager} for interacting with the status bar. 
 * 
 * @see #getSystemService 
 * @see android.app.StatusBarManager 
 * @hide 
 */  
public static final String STATUS_BAR_SERVICE = "statusbar";  

表明该service不对外提供,如果要调用的话需要在源码上编译,才能调用到标记为@hide的接口。也可以将源码编译出来的classes.jar包添加到工程里面。

StatusBarManager提供了一些有用的接口,像disable()方法正是我们需要的,一些系统级的应用也是调用的该方法禁止StatusBar下拉的,比如电话、锁屏模块。想要调用该方法,你还需要以下权限:

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

获取StatusBarManager实例

mStatusBarManager = (StatusBarManager) mContext.getSystemService(Context.STATUS_BAR_SERVICE);

禁止下拉和解除禁止

mStatusBarManager.disable(StatusBarManager.DISABLE_EXPAND); //禁止下拉
mStatusBarManager.disable(StatusBarManager.DISABLE_NONE);  //解除禁止

整个系统不可下拉

第一种就很简单了,只需要修改系统远吗就能实现所有的状态栏不能下拉:(我这里用的5.1的源码)

	/**
     * Disable some features in the status bar.  Pass the bitwise-or of the DISABLE_* flags.
     * To re-enable everything, pass {@link #DISABLE_NONE}.
     */
    public void disable(int what) {
        try {
            final IStatusBarService svc = getService();
            if (svc != null) {
	            //svc.disable(what, mToken, mContext.getPackageName());//--remove this
                mService.disable(DISABLE_EXPAND, mToken, mContext.getPackageName()); //++added this
            }
        } catch (RemoteException ex) {
            throw new RuntimeException(ex);
        }
    }

然后参照这篇文章《修改framework后刷入系统》开机重启,一气呵成,搞定,拉不下来了。

应用运行中不可下拉(系统应用)

如果是系统级应用,也就是手机厂家植入的应用,可以使用调用StatusBarManager 的disable(int)的方法来进行屏蔽,参数如下:

	public static final int DISABLE_EXPAND = 0x00000001;  
    public static final int DISABLE_NOTIFICATION_ICONS = 0x00000002;  
    public static final int DISABLE_NOTIFICATION_ALERTS = 0x00000004;  
    public static final int DISABLE_NOTIFICATION_TICKER = 0x00000008;  
    public static final int DISABLE_NONE = 0x00000000;  

具体是这样实现的:

private StatusBarManager mStatusBarManager;  
mStatusBarManager = (StatusBarManager)getSystemService(Context.STATUS_BAR_SERVICE);  

@Override  
   protected void onResume() {  
       if (DBG) log("onResume()...");  
       super.onResume();  
         
       mStatusBarManager.disable(StatusBarManager.DISABLE_EXPAND);  

	   ...
}  
    

应用运行中不可下拉(非系统应用)

但是如果是在应用层上的,disable方法因为权限问题无法使用(如果一定要使用必须具有系统签名)。这个时候可以使用collapse()方法,现在的小米锁屏和360锁屏都是使用该方法。

	public void onWindowFocusChanged(boolean hasFocus) {  
        disableStatusBar();  
        super.onWindowFocusChanged(hasFocus);  
    }  
  
    public void disableStatusBar(){  
        try {  
            Object service = getSystemService("statusbar");  
            Class<?> claz = Class.forName("android.app.StatusBarManager");  
            Method expand = claz.getMethod("disable");  
            expand.invoke(service);  
        } catch (Exception e) {  
            e.printStackTrace();  
    }  

为了方便大家理解,我把StatusBarManager 这个类贴出来:
vim frameworks/base/core/java/android/app/StatusBarManager.java

/*
 * Copyright (C) 2007 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */


package android.app;

import android.content.Context;
import android.os.Binder;
import android.os.RemoteException;
import android.os.IBinder;
import android.os.ServiceManager;
import android.util.Slog;
import android.view.View;

import com.android.internal.statusbar.IStatusBarService;

/**
 * Allows an app to control the status bar.
 *
 * @hide
 */
public class StatusBarManager {

    public static final int DISABLE_EXPAND = View.STATUS_BAR_DISABLE_EXPAND;
    public static final int DISABLE_NOTIFICATION_ICONS = View.STATUS_BAR_DISABLE_NOTIFICATION_ICONS;
    public static final int DISABLE_NOTIFICATION_ALERTS
            = View.STATUS_BAR_DISABLE_NOTIFICATION_ALERTS;
    @Deprecated
    public static final int DISABLE_NOTIFICATION_TICKER
            = View.STATUS_BAR_DISABLE_NOTIFICATION_TICKER;
    public static final int DISABLE_SYSTEM_INFO = View.STATUS_BAR_DISABLE_SYSTEM_INFO;
    public static final int DISABLE_HOME = View.STATUS_BAR_DISABLE_HOME;
    public static final int DISABLE_RECENT = View.STATUS_BAR_DISABLE_RECENT;
    public static final int DISABLE_BACK = View.STATUS_BAR_DISABLE_BACK;
    public static final int DISABLE_CLOCK = View.STATUS_BAR_DISABLE_CLOCK;
    public static final int DISABLE_SEARCH = View.STATUS_BAR_DISABLE_SEARCH;

    @Deprecated
    public static final int DISABLE_NAVIGATION = 
            View.STATUS_BAR_DISABLE_HOME | View.STATUS_BAR_DISABLE_RECENT;

    public static final int DISABLE_NONE = 0x00000000;

    public static final int DISABLE_MASK = DISABLE_EXPAND | DISABLE_NOTIFICATION_ICONS
            | DISABLE_NOTIFICATION_ALERTS | DISABLE_NOTIFICATION_TICKER
            | DISABLE_SYSTEM_INFO | DISABLE_RECENT | DISABLE_HOME | DISABLE_BACK | DISABLE_CLOCK
            | DISABLE_SEARCH;

    public static final int NAVIGATION_HINT_BACK_ALT      = 1 << 0;
    public static final int NAVIGATION_HINT_IME_SHOWN     = 1 << 1;

    public static final int WINDOW_STATUS_BAR = 1;
    public static final int WINDOW_NAVIGATION_BAR = 2;

    public static final int WINDOW_STATE_SHOWING = 0;
    public static final int WINDOW_STATE_HIDING = 1;
    public static final int WINDOW_STATE_HIDDEN = 2;

    private Context mContext;
    private IStatusBarService mService;
    private IBinder mToken = new Binder();

    StatusBarManager(Context context) {
        mContext = context;
    }

    private synchronized IStatusBarService getService() {
        if (mService == null) {
            mService = IStatusBarService.Stub.asInterface(
                    ServiceManager.getService(Context.STATUS_BAR_SERVICE));
            if (mService == null) {
                Slog.w("StatusBarManager", "warning: no STATUS_BAR_SERVICE");
            }
        }
        return mService;
    }

    /**
     * 敲黑板:重点就在这里
     * Disable some features in the status bar.  Pass the bitwise-or of the DISABLE_* flags.
     * To re-enable everything, pass {@link #DISABLE_NONE}.
     */
    public void disable(int what) {
        try {
            final IStatusBarService svc = getService();
            if (svc != null) {
 	          //replace what to disable
              svc.disable(what, mToken, mContext.getPackageName());
            }
        } catch (RemoteException ex) {
            // system process is dead anyway.
            throw new RuntimeException(ex);
        }
    }
    
    /**
     * Expand the notifications panel.
     */
    public void expandNotificationsPanel() {
        try {
            final IStatusBarService svc = getService();
            if (svc != null) {
                svc.expandNotificationsPanel();
            }
        } catch (RemoteException ex) {
            // system process is dead anyway.
            throw new RuntimeException(ex);
        }
    }
    
    /**
     * Collapse the notifications and settings panels.
     */
    public void collapsePanels() {
        try {
            final IStatusBarService svc = getService();
            if (svc != null) {
                svc.collapsePanels();
            }
        } catch (RemoteException ex) {
            // system process is dead anyway.
            throw new RuntimeException(ex);
        }
    }

    /**
     * Expand the settings panel.
     */
    public void expandSettingsPanel() {
        try {
            final IStatusBarService svc = getService();
            if (svc != null) {
                svc.expandSettingsPanel();
            }
        } catch (RemoteException ex) {
            // system process is dead anyway.
            throw new RuntimeException(ex);
        }
    }

    public void setIcon(String slot, int iconId, int iconLevel, String contentDescription) {
        try {
            final IStatusBarService svc = getService();
            if (svc != null) {
                svc.setIcon(slot, mContext.getPackageName(), iconId, iconLevel,
                    contentDescription);
            }
        } catch (RemoteException ex) {
            // system process is dead anyway.
            throw new RuntimeException(ex);
        }
    }

    public void removeIcon(String slot) {
        try {
            final IStatusBarService svc = getService();
            if (svc != null) {
                svc.removeIcon(slot);
            }
        } catch (RemoteException ex) {
            // system process is dead anyway.
            throw new RuntimeException(ex);
        }
    }

    public void setIconVisibility(String slot, boolean visible) {
        try {
            final IStatusBarService svc = getService();
            if (svc != null) {
                svc.setIconVisibility(slot, visible);
            }
        } catch (RemoteException ex) {
            // system process is dead anyway.
            throw new RuntimeException(ex);
        }
    }

    /** @hide */
    public static String windowStateToString(int state) {
        if (state == WINDOW_STATE_HIDING) return "WINDOW_STATE_HIDING";
        if (state == WINDOW_STATE_HIDDEN) return "WINDOW_STATE_HIDDEN";
        if (state == WINDOW_STATE_SHOWING) return "WINDOW_STATE_SHOWING";
        return "WINDOW_STATE_UNKNOWN";
    }
}

示范案例

例子1:
公司有个需求当拨打电话在前台执行时,状态栏下拉不了,而在后台执行时,状态栏则可以下拉,此时需要修改的是phone应用。
在电话的呼出流程中,我们最后需要按下拨号键,才能将电话拨打出去,那么在按下拨号键之后,我们可以看到会弹出一个界面
(1),显示拨号信息以及一些其他信息,这个界面就是我们的InCallScreen界面。当然,在来电
(2)的时候,弹出的界面依然是InCallScreen,在我们接通电话
(3)之后显示的那个界面仍然是InCallScreen。也就是说在通话过程中,我们一直可见并操作的那个界面就是InCallScreen
在类com.android.phone. InCallScreen.java

private StatusBarManager mStatusBarManager;  
mStatusBarManager = (StatusBarManager)getSystemService(Context.STATUS_BAR_SERVICE);  
@Override  
   protected void onResume() {  
       if (DBG) log("onResume()...");  
       super.onResume();  
         
       mStatusBarManager.disable(StatusBarManager.DISABLE_EXPAND);  
	   ... 
}       
@Override  
   protected void onPause() {  
       if (DBG) log("onPause()...");  
       super.onPause();  
         
       mStatusBarManager.disable(StatusBarManager.DISABLE_NONE);  
	   ... 
}     

例子2:公司有个需求在安全模式下状态栏下拉不了,android模式下状态栏可以下拉(两个模式的切换广播通知),这个需求我们可以使用上述方法,也可以直接在systemui中修改,此时我们使用第二种方法。
status_bar.xml:下拉部分就是触摸这个View,因此可以在这个视图中查看触摸事件。(状态栏部分:包括浮动通知,耳机、蓝牙、电池、信号、闹钟等图标)
packagecom.android.systemui.statusbar.phone;

public classPhoneStatusBarView extends PanelBar {  
@Override  
   public boolean panelsEnabled() { //可以在此处修改  
       return ((mBar.mDisabled & StatusBarManager.DISABLE_EXPAND) == 0);  
    }  
}  

上述方法中可以修改为如下:

public boolean panelsEnabled() {  
if(安全模式){  
                       return false;  
             }else{  
                       return ((mBar.mDisabled &StatusBarManager.DISABLE_EXPAND) == 0);  
             }  
}  

package com.android.systemui.statusbar.phone;

public classPanelBar extends FrameLayout {  
   @Override  
    publicboolean onTouchEvent(MotionEvent event) {  
       // Allow subclasses to implement enable/disable semantics  
        if (!panelsEnabled()) {  
           if (event.getAction() == MotionEvent.ACTION_DOWN) {  
                Slog.v(TAG,String.format("onTouch: all panels disabled, ignoring touch at(%d,%d)",  
                        (int)event.getX(), (int) event.getY()));  
           }  
           return false;  
       }  
	public booleanpanelsEnabled() {//父类PhoneStatusBarView重写了  
       return true;  
    }  
	...  
}  
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

疯人院的院长大人

给点实际性的支持不?

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值