Cambiar el diseño Los parámetros de los encabezados de chat siempre visibles a no siempre visibles

Estoy intentando agregar una vista que estoy generando a través de un servicio. El código que estoy usando se basa enChatheads de Facebook que siempre están visibles, independientemente del estado de las aplicaciones. También se muestran sobre cualquier otra cosa:

Ahora deseo restringir la cabeza del chat a la aplicación activa. Específicamente, estoy lidiando con una excepción de token incorrecto cada vez que cambio Window.LayoutParams de TYPE_PHONE a TYPE_DRAWN_APPLICATION.

MI PREGUNTA: Sé que debo pasar el token de ventana correcto a los LayoutParams, pero parece que no puedo entender cómo hacerlo correctamente. Cualquier consejo sería muy apreciado.

Aquí está mi código:

//Actividad principal

private void addNewBubble() {
        BubbleLayout bubbleView = (BubbleLayout)LayoutInflater.from(MainActivity.this).inflate(R.layout.bubble_layout, null);
        bubblesManager.addBubble(bubbleView, 60, 20);
}

// initializes Bubbles Manager
private void initializeBubblesManager() {
        bubblesManager = new BubblesManager.Builder(this)
                .setTrashLayout(R.layout.task_bubble_trash_layout)
                .setInitializationCallback(new OnInitializedCallback() {
                    @Override
                    public void onInitialized() {
                        addNewBubble(); // Called when addNewBubble is initialized and the bubble data is loaded. When used on devices running API 18 or below, this function is always called.

                    }
                })
                .build();
        bubblesManager.initialize();
    }

// initializes Bubbles Manager
        private void initializeBubblesManager() {
            bubblesManager = new BubblesManager.Builder(this)
                    .setTrashLayout(R.layout.task_bubble_trash_layout)
                    .setInitializationCallback(new OnInitializedCallback() {
                        @Override
                        public void onInitialized() {
                            addNewBubble(); // Called when addNewBubble is initialized and the bubble data is loaded. When used on devices running API 18 or below, this function is always called.

                        }
                    })
                    .build();
            bubblesManager.initialize();
        }

// XML - Bubble_layout personalizado

<com.momely.bubbles.BubbleLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:clipChildren="false"
    android:clipToPadding="false">

    <ImageView
        android:id="@+id/avatar"
        android:layout_width="70dp"
        android:layout_height="70dp"
        android:layout_gravity="center"
        android:background="@drawable/profile_decorator"
        android:src="@drawable/round_button"
        android:scaleType="centerCrop"/>

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textColor="@color/white"
        android:textSize="15sp"
        android:layout_marginTop="2dp"
        android:layout_marginLeft="2dp"
        android:paddingLeft="4dp"
        android:paddingRight="4dp"
        android:background="@drawable/bubble_counter_bkg"
        android:text="1"/>

</com.momely.bubbles.BubbleLayout>

// en bubbleManager

public class BubblesManager {
    private static BubblesManager INSTANCE;
    private Context context;
    private boolean bounded;
    private BubblesService bubblesService;
    private int trashLayoutResourceId;
    private OnInitializedCallback listener;


    //getInstance (called in Builder below)
    private static BubblesManager getInstance(Context context){
        if (INSTANCE == null) {
            INSTANCE = new BubblesManager(context);
        }
        return INSTANCE;
    }

    //Binds the service to the application
    private ServiceConnection bubbleServiceConnection = new ServiceConnection(){
        @Override
        public void onServiceConnected(ComponentName name, IBinder service){
            BubblesService.BubblesServiceBinder binder = (BubblesService.BubblesServiceBinder)service;
            BubblesManager.this.bubblesService = binder.getService();
            configureBubblesService();
            bounded = true;
            if(listener != null){
                listener.onInitialized();
            }
        }

   //Initializes Bubbles Manager
   private BubblesManager(Context context){
        this.context = context;
        }

   //Initializes the service
   public void initialize(){
        context.bindService(new Intent(context, BubblesService.class),
            bubbleServiceConnection,
            Context.BIND_AUTO_CREATE);
        }

    public void addBubble(BubbleLayout bubble, int x, int y){
        if(bounded){
            bubblesService.addBubble(bubble, x, y);
            Log.d("Bubble", "Bubble created");
        }

    //Builder class
    public static class Builder {
        private BubblesManager bubblesManager;

        //Builder constructor
        public Builder(Context context){
            this.bubblesManager = getInstance(context);
        }

        //Sets initialization Callbacks - a callback is when we provide a function as an argument to another function in order to enforce the order of operations.
        public Builder setInitializationCallback(OnInitializedCallback listener){
            bubblesManager.listener = listener;
            return this;
        }

        //Sets Trash Layout
        public Builder setTrashLayout(int trashLayoutResourceId){
            bubblesManager.trashLayoutResourceId = trashLayoutResourceId;
            return this;
        }

        //Triggers BubbleManager;
        public BubblesManager build(){
            return bubblesManager;
        }
    }
}

// en burbujas Servicio

imports...


public class BubblesService extends Service{
    private BubblesServiceBinder binder = new BubblesServiceBinder();
    private List<BubbleLayout> bubbles = new ArrayList<>();
    private BubbleTrashLayout bubblesTrash;
    private WindowManager windowManager;
    private BubblesLayoutCoordinator layoutCoordinator;

    //overrides the IBind method
    @Override
    public IBinder onBind(Intent intent){
        return binder;
    }


    //overrides the onUnbind method
    @Override
    public boolean onUnbind(Intent intent){
        for (BubbleLayout bubble : bubbles){
            recycleBubble(bubble);
        }
        bubbles.clear();
        return super.onUnbind(intent);
   }


    //Gets the Windows Manager
    private WindowManager getWindowManager(){
        if (windowManager ==null){
            windowManager = (WindowManager)getSystemService(WINDOW_SERVICE);
        }
        return windowManager;
    }

    // Adds view to the Window
    public void addBubble(BubbleLayout bubble, int x, int y){
        WindowManager.LayoutParams layoutParams = buildLayoutParamsForBubble(bubble, x,y);
        layoutParams.token = bubble.getApplicationWindowToken();
        bubble.setWindowManager(getWindowManager());
        bubble.setViewParams(layoutParams);
        bubble.setLayoutCoordinator(layoutCoordinator);
        bubbles.add(bubble);
        addViewToWindow(bubble);
    }


    // Initializes the Layout Cocordinator
    private void initializeLayoutCoordinator(){
        layoutCoordinator = new BubblesLayoutCoordinator.Builder(this)
                .setWindowManager(getWindowManager())
                .setTrashView(bubblesTrash)
                .setTrashView(bubblesTrash)
                .build();
    }

    //Adds view to the Window
    private void addViewToWindow(final BubbleBaseLayout view){
        new Handler(Looper.getMainLooper()).post(new Runnable(){
            @Override
            public void run(){
                getWindowManager().addView(view, view.getViewParams());
            }
        });
    }

    //BUILDING LAYOUT PARAMS --> THIS IS WHERE THE TYPE IS SET
    private WindowManager.LayoutParams buildLayoutParamsForBubble(BubbleLayout bubble, int x, int y){
        WindowManager.LayoutParams params = new WindowManager.LayoutParams(
                WindowManager.LayoutParams.WRAP_CONTENT,
                WindowManager.LayoutParams.WRAP_CONTENT,
                WindowManager.LayoutParams.TYPE_DRAWN_APPLICATION, //!!!! WHEN this is set to TYPE_PHONE the chat head stays on the screen even if the application is onPause.
                WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
                PixelFormat.TRANSPARENT);
        params.gravity = Gravity.TOP | Gravity.START;
        params.token = bubble.getApplicationWindowToken();
        params.x = x;
        params.y = y;
        return params;
    }


    //defines the BubblesService Binder service
    public class BubblesServiceBinder extends Binder {
        public BubblesService getService(){
            return BubblesService.this;
        }
    }

}

/// ERROR ESTOY RECIBIENDO

E/AndroidRuntime: FATAL EXCEPTION: main
   Process: com.momely.mascapone, PID: 16638
   android.view.WindowManager$BadTokenException: Unable to add window -- token null is not for an application
       at android.view.ViewRootImpl.setView(ViewRootImpl.java:683)
       at android.view.WindowManagerGlobal.addView(WindowManagerGlobal.java:342)
       at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:93)
       at com.momely.bubbles.BubblesService$2.run(BubblesService.java:115)
       at android.os.Handler.handleCallback(Handler.java:751)
       at android.os.Handler.dispatchMessage(Handler.java:95)
       at android.os.Looper.loop(Looper.java:154)
       at android.app.ActivityThread.main(ActivityThread.java:6119)
       at java.lang.reflect.Method.invoke(Native Method)
       at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:886)
       at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:776)

¿Algún consejo sobre cómo podría limitar la cabeza del chat a la ventana de la aplicación sin que permanezca en la pantalla cuando la aplicación está en Pausa?

Z

Respuestas a la pregunta(1)

Su respuesta a la pregunta