首页 > 解决方案 > 创建新的状态栏不适用于 targetSdkVersion 30

问题描述

我需要覆盖我的一个应用程序的状态栏。

以前,当我使用targetSdkVersion21 时,代码块运行良好,但当我切换targetSdkVersion到 30 时,它崩溃并出现以下错误:

2021-08-16 17:50:40.920 6309-6309/myapp.com E/AndroidRuntime: FATAL EXCEPTION: main
    Process: myapp.com, PID: 6309
    java.lang.RuntimeException: Unable to create application myapp.com.App: android.view.WindowManager$BadTokenException: Unable to add window android.view.ViewRootImpl$W@47a3c01 -- permission denied for this window type
        at android.app.ActivityThread.handleBindApplication(ActivityThread.java:6325)
        at android.app.ActivityThread.access$1800(ActivityThread.java:222)
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1862)
        at android.os.Handler.dispatchMessage(Handler.java:102)
        at android.os.Looper.loop(Looper.java:158)
        at android.app.ActivityThread.main(ActivityThread.java:7230)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1230)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1120)
     Caused by: android.view.WindowManager$BadTokenException: Unable to add window android.view.ViewRootImpl$W@47a3c01 -- permission denied for this window type
        at android.view.ViewRootImpl.setView(ViewRootImpl.java:878)
        at android.view.WindowManagerGlobal.addView(WindowManagerGlobal.java:337)
        at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:109)
        at myapp.com.App.showCustomStatusBar(App.java:144)
        at myapp.com.App.onCreate(App.java:67)
        at android.app.Instrumentation.callApplicationOnCreate(Instrumentation.java:1037)
        at android.app.ActivityThread.handleBindApplication(ActivityThread.java:6322)
        at android.app.ActivityThread.access$1800(ActivityThread.java:222) 
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1862) 
        at android.os.Handler.dispatchMessage(Handler.java:102) 
        at android.os.Looper.loop(Looper.java:158) 
        at android.app.ActivityThread.main(ActivityThread.java:7230) 
        at java.lang.reflect.Method.invoke(Native Method) 
        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1230) 
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1120)

下面是显示状态栏的代码:

 

WindowManager windowManager = (WindowManager) getSystemService(WINDOW_SERVICE);
if(customToolbar == null) {
    customToolbar = new CustomToolbar(getBaseContext());
}
int viewType;
WindowManager.LayoutParams layoutParams = new WindowManager.LayoutParams(
        WindowManager.LayoutParams.MATCH_PARENT,
        getStatusBarHeight(),
        // Allows the view to be on top of the StatusBar
        WindowManager.LayoutParams.TYPE_SYSTEM_ERROR,
        // Keeps the button presses from going to the background window
        WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE |
                // Enables the notification to recieve touch events
                WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL |
                // Draws over status bar
                WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN,
        PixelFormat.OPAQUE);

layoutParams.gravity = Gravity.TOP|Gravity.CENTER;
windowManager.addView(customToolbar, layoutParams); //Crashes on this line

我尝试使用:

int viewType;
if(Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
    viewType = WindowManager.LayoutParams.TYPE_PHONE;
} else {
    viewType = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
}

代替 :

WindowManager.LayoutParams.TYPE_SYSTEM_ERROR

但它以同样的方式崩溃。

我还添加Permissions到清单:

<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
<uses-permission android:name="android.permission.WAKE_LOCK" />

标签: androidstatusbarandroid-windowmanager

解决方案


我尝试了多个选项(WindowManager.LayoutParams.TYPE_PHONEWindowManager.LayoutParams.TYPE_SYSTEM_ALERTWindowManager.LayoutParams.TYPE_APPLICATION_PANEL,但它们都不起作用,所以当我WindowManager.LayoutParams.TYPE_TOAST在我的 API 21 手机上使用时,它不再抛出错误并开始工作,但我还必须在那里进行 if 切换。

WindowManager windowManager = (WindowManager) getSystemService(WINDOW_SERVICE);
if(customToolbar == null) {
    customToolbar = new CustomToolbar(getBaseContext());
}
int viewType;
if(Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
    viewType = WindowManager.LayoutParams.TYPE_TOAST;
} else {
    viewType = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
}
WindowManager.LayoutParams layoutParams = new WindowManager.LayoutParams(
        WindowManager.LayoutParams.MATCH_PARENT,
        getStatusBarHeight(),
        // Allows the view to be on top of the StatusBar
        viewType,
        // Keeps the button presses from going to the background window
        WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE |
                // Enables the notification to receive touch events
                WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL |
                // Draws over status bar
                WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN,
        PixelFormat.OPAQUE);

layoutParams.gravity = Gravity.TOP|Gravity.CENTER;
windowManager.addView(customToolbar, layoutParams);

推荐阅读