【问题标题】:Android system overlay not shown outside my appAndroid 系统覆盖未显示在我的应用程序之外
【发布时间】:2014-05-13 16:15:47
【问题描述】:

我需要在任何正在运行的应用程序之上显示一个系统覆盖窗口。它工作正常,但只有当我的应用程序的活动处于前台时。这是我使用的代码:

params = new WindowManager.LayoutParams(
                    WindowManager.LayoutParams.WRAP_CONTENT,
                    WindowManager.LayoutParams.WRAP_CONTENT,
                    WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY,
                    WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | 
                    WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE |
                    WindowManager.LayoutParams.FLAG_DIM_BEHIND |
                    WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON | 
                    WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED |
                    WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON |
                    WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD,
                    PixelFormat.TRANSLUCENT);

params.gravity = Gravity.CENTER | Gravity.TOP;
params.dimAmount = 0.3f;
wm = (WindowManager) ctx.getSystemService(Context.WINDOW_SERVICE);

    mainAlertView = View.inflate(ctx, R.layout.system_alert_view, null);

    wm.addView(mainAlertView, params);

添加到 WindowManager 的视图包含我在运行时添加子视图的空 LinearLayout:

    mainAlertLayout.addView(childView);

清单 xml 已定义 SYSTEM_ALERT_WINDOW 权限:

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

当我的活动在前台运行时,这一切都运行良好。一旦我切换到任何其他应用程序或主屏幕,就不会显示任何覆盖。我调试了代码,它确实在运行 wm.addView(),并且它没有抛出任何异常。我也玩过 LayoutParams 标志(删除了 KEEP_SCREEN_ON 和相关等),但没有任何区别。

Android 4.4.2 固件

【问题讨论】:

  • 我记得当我尝试做这些事情时,据我所知,Context 必须是应用程序上下文。我不能成为活动。你在用什么?
  • "ctx" 包含主要活动 getApplicationContext() 调用返回的任何内容
  • 那是应用程序上下文。祝你好运。
  • TYPE_SYSTEM_ALERT 而不是 TYPE_SYSTEM_OVERLAY?
  • 我不需要警报。我需要一个始终在顶部的半透明覆盖窗口。 TYPE_SYSTEM_OVERLAY 正是我所需要的,它工作正常......只要我的活动在前台

标签: android android-layout layoutparams


【解决方案1】:

您需要创建一个service 以保持系统覆盖(警报)即使在您的应用程序关闭时也能显示。

创建一个简单的服务,我会调用FloatingService,它会在调用onStartCommand时显示overlay(alert)。返回START_STICKY 以保持服务在后台运行。

    public class FloatingService extends Service {
      private WindowManager windowManager;
      private View floatingView;

     WindowManager.LayoutParams params;
    @Override
     public IBinder onBind(Intent intent) {
        return null;
      }

     @Override
     public int onStartCommand(Intent intent, int flag, int startId){
      // show the alert her
      windowManager = (WindowManager) getSystemService(WINDOW_SERVICE);
       // use your custom view here
        floatingView = View.inflate(getBaseContext(),R.layout.floating_layout,null);            //floatingView.setOnTouchListener(mOnTouchListener);
        params = new WindowManager.LayoutParams(
                WindowManager.LayoutParams.WRAP_CONTENT,
                WindowManager.LayoutParams.WRAP_CONTENT,
                WindowManager.LayoutParams.TYPE_PHONE,
                WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD,
                PixelFormat.TRANSLUCENT);
           params.gravity = Gravity.CENTER | Gravity.CENTER;
        // add the view to window manger
        windowManager.addView(floatingView, params);
      return START_STICKY;
     }
 }

向视图添加一个监听器,以便您可以在需要时关闭覆盖(警报)

      floatingView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                windowManager.removeView(floatingView);
                floatingView = null;
            }
        });

最后,在 manifest 中注册服务

 <service android:name="com.example.app.services.FloatingService" />

还有System Alert权限

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

【讨论】:

  • 服务的问题是它不一定在UI线程中运行,因此我不能直接使用addView调用。无论哪种方式,我都不明白为什么它必须是一项服务?我已经运行了一个后台服务,它通过事件总线与我的“系统覆盖”管理器通信,这还不够吗?
  • 我想通了。我会发布我自己的答案,但因为它的清晰性和广泛的说明而赞成你的回答
【解决方案2】:

问题是我在主视图的 post() 方法中运行 addView() 调用:

mainView.post(new Runnable() {
 public void run() {
  wm.add(mainView);
 }
);

如果我只是在主线程中运行它,它就可以正常工作。我使用 de.greenrobot.eventbus,它非常简单地将 Runnable 发布到事件总线并确保它在主线程中执行:

public void onEventMainThread(UIRunnableEvent event) {
    event.r.run();
}

public static class UIRunnableEvent {
    protected Runnable r;

    protected UIRunnableEvent(Runnable r) {
        this.r = r;
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-04-30
    • 2016-10-12
    • 1970-01-01
    • 1970-01-01
    • 2013-01-19
    • 1970-01-01
    • 2013-05-02
    • 2012-08-29
    相关资源
    最近更新 更多