Próbuję dodać widok generuję za pośrednictwem usługi. Kod, którego używam, jest oparty na Facebook Chatheads, które są zawsze widoczne, niezależnie od stanu aplikacji. Są one również wyświetlane powyżej cokolwiek innego TOO:Zmiana układuParams zawsze widocznych Heads Chat nie zawsze widoczne
I teraz chcą ograniczyć głowę czat do aktywnej aplikacji. W szczególności mam do czynienia z wyjątkiem Bad Token, gdy tylko zmieniam Window.LayoutParams z TYPE_PHONE na TYPE_DRAWN_APPLICATION.
MOJE PYTANIE: Wiem, że jestem zobowiązany przekazać prawidłowy token okna do LayoutParams, ale nie mogę wymyślić, jak to zrobić poprawnie. Każda rada byłaby wysoko ceniona.
Oto mój kod:
// Main Activity
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 - Niestandardowe Bubble_layout
<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>
// w bubblesManager
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;
}
}
}
// w bąbelkach Usługa
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 Otrzymuję
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)
Wszelkie porady, w jaki sposób mogę ograniczyć czat głowę do okna aplikacji bez pozostała ona na ekranie, gdy aplikacja jest włączona pauza?
Z
Dlaczego rozszerzasz 'Service'? –
Dobre pytanie. Wydaje mi się, że rozszerzenie usługi pozwala nam uruchomić BubblesService jako usługę, którą możemy powiązać z oknem? – Z101
Nice Guess. W tym celu należy uruchomić 'BubblesService' i powiązać składnik interfejsu użytkownika przed uzyskaniem dostępu do' addBubble' –