package com.flipkart.chatheads.ui.container; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.res.Configuration; import android.graphics.Color; import android.graphics.PixelFormat; import android.view.Gravity; import android.view.KeyEvent; import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup; import android.view.WindowManager; import android.widget.FrameLayout; import com.flipkart.chatheads.ui.ChatHead; import com.flipkart.chatheads.ui.ChatHeadArrangement; import com.flipkart.chatheads.ui.ChatHeadManager; import com.flipkart.chatheads.ui.FrameChatHeadContainer; import com.flipkart.chatheads.ui.HostFrameLayout; import com.flipkart.chatheads.ui.MaximizedArrangement; import com.flipkart.chatheads.ui.MinimizedArrangement; import static android.content.Context.WINDOW_SERVICE; import static android.view.ViewGroup.LayoutParams.MATCH_PARENT; import static android.view.WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM; import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE; import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE; import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL; import static android.view.WindowManager.LayoutParams.TYPE_PHONE; import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY; /** * Created by kiran.kumar on 08/11/16. */ public class WindowManagerContainer extends FrameChatHeadContainer { /** * A transparent view of the size of chat head which capture motion events and delegates them to the real view (frame layout) * This view is required since window managers will delegate the touch events to the window beneath it only if they are outside the bounds. * {@link android.view.WindowManager.LayoutParams#FLAG_NOT_TOUCH_MODAL} */ private View motionCaptureView; private int cachedHeight; private int cachedWidth; private WindowManager windowManager; private ChatHeadArrangement currentArrangement; private boolean motionCaptureViewAdded; public WindowManagerContainer(Context context) { super(context); } @Override public void onInitialized(ChatHeadManager manager) { super.onInitialized(manager); motionCaptureView = new MotionCaptureView(getContext()); MotionCapturingTouchListener listener = new MotionCapturingTouchListener(); motionCaptureView.setOnTouchListener(listener); registerReceiver(getContext()); } public void registerReceiver(Context context) { context.registerReceiver(new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { HostFrameLayout frameLayout = getFrameLayout(); if (frameLayout != null) { frameLayout.minimize(); } } }, new IntentFilter(Intent.ACTION_CLOSE_SYSTEM_DIALOGS)); } public WindowManager getWindowManager() { if (windowManager == null) { windowManager = (WindowManager) getContext().getSystemService(WINDOW_SERVICE); } return windowManager; } protected void setContainerHeight(View container, int height) { WindowManager.LayoutParams layoutParams = getOrCreateLayoutParamsForContainer(container); layoutParams.height = height; getWindowManager().updateViewLayout(container, layoutParams); } protected void setContainerWidth(View container, int width) { WindowManager.LayoutParams layoutParams = getOrCreateLayoutParamsForContainer(container); layoutParams.width = width; getWindowManager().updateViewLayout(container, layoutParams); } protected WindowManager.LayoutParams getOrCreateLayoutParamsForContainer(View container) { WindowManager.LayoutParams layoutParams = (WindowManager.LayoutParams) container.getLayoutParams(); if (layoutParams == null) { layoutParams = createContainerLayoutParams(false); container.setLayoutParams(layoutParams); } return layoutParams; } protected void setContainerX(View container, int xPosition) { WindowManager.LayoutParams layoutParams = getOrCreateLayoutParamsForContainer(container); layoutParams.x = xPosition; getWindowManager().updateViewLayout(container, layoutParams); } protected int getContainerX(View container) { WindowManager.LayoutParams layoutParams = getOrCreateLayoutParamsForContainer(container); return layoutParams.x; } protected void setContainerY(View container, int yPosition) { WindowManager.LayoutParams layoutParams = getOrCreateLayoutParamsForContainer(container); layoutParams.y = yPosition; getWindowManager().updateViewLayout(container, layoutParams); } protected int getContainerY(View container) { WindowManager.LayoutParams layoutParams = getOrCreateLayoutParamsForContainer(container); return layoutParams.y; } protected WindowManager.LayoutParams createContainerLayoutParams(boolean focusable) { int focusableFlag; if (focusable) { focusableFlag = FLAG_NOT_TOUCH_MODAL; } else { focusableFlag = FLAG_NOT_TOUCHABLE | FLAG_NOT_FOCUSABLE; } WindowManager.LayoutParams layoutParams = new WindowManager.LayoutParams(MATCH_PARENT, MATCH_PARENT, TYPE_PHONE, focusableFlag, PixelFormat.TRANSLUCENT); layoutParams.x = 0; layoutParams.y = 0; layoutParams.gravity = Gravity.TOP | Gravity.START; return layoutParams; } @Override public void addContainer(View container, boolean focusable) { WindowManager.LayoutParams containerLayoutParams = createContainerLayoutParams(focusable); addContainer(container, containerLayoutParams); } public void addContainer(View container, WindowManager.LayoutParams containerLayoutParams) { container.setLayoutParams(containerLayoutParams); getWindowManager().addView(container, containerLayoutParams); } @Override public void setViewX(View view, int xPosition) { super.setViewX(view, xPosition); if (view instanceof ChatHead) { boolean hero = ((ChatHead) view).isHero(); if (hero && currentArrangement instanceof MinimizedArrangement) { setContainerX(motionCaptureView, xPosition); setContainerWidth(motionCaptureView, view.getMeasuredWidth()); } } } @Override public void setViewY(View view, int yPosition) { super.setViewY(view, yPosition); if (view instanceof ChatHead && currentArrangement instanceof MinimizedArrangement) { boolean hero = ((ChatHead) view).isHero(); if (hero) { setContainerY(motionCaptureView, yPosition); setContainerHeight(motionCaptureView, view.getMeasuredHeight()); } } } @Override public void onArrangementChanged(ChatHeadArrangement oldArrangement, ChatHeadArrangement newArrangement) { currentArrangement = newArrangement; if (oldArrangement instanceof MinimizedArrangement && newArrangement instanceof MaximizedArrangement) { // about to be maximized WindowManager.LayoutParams layoutParams = getOrCreateLayoutParamsForContainer(motionCaptureView); layoutParams.flags |= FLAG_NOT_FOCUSABLE | FLAG_NOT_TOUCHABLE; windowManager.updateViewLayout(motionCaptureView, layoutParams); layoutParams = getOrCreateLayoutParamsForContainer(getFrameLayout()); layoutParams.flags &= ~FLAG_NOT_FOCUSABLE; //add focusability layoutParams.flags &= ~FLAG_NOT_TOUCHABLE; //add focusability layoutParams.flags |= FLAG_NOT_TOUCH_MODAL; windowManager.updateViewLayout(getFrameLayout(), layoutParams); setContainerX(motionCaptureView, 0); setContainerY(motionCaptureView, 0); setContainerWidth(motionCaptureView, getFrameLayout().getMeasuredWidth()); setContainerHeight(motionCaptureView, getFrameLayout().getMeasuredHeight()); } else { // about to be minimized WindowManager.LayoutParams layoutParams = getOrCreateLayoutParamsForContainer(motionCaptureView); layoutParams.flags |= FLAG_NOT_FOCUSABLE; //remove focusability layoutParams.flags &= ~FLAG_NOT_TOUCHABLE; //add touch layoutParams.flags |= FLAG_NOT_TOUCH_MODAL; //add touch windowManager.updateViewLayout(motionCaptureView, layoutParams); layoutParams = getOrCreateLayoutParamsForContainer(getFrameLayout()); layoutParams.flags |= FLAG_NOT_FOCUSABLE | FLAG_NOT_TOUCHABLE; windowManager.updateViewLayout(getFrameLayout(), layoutParams); } } @Override public void addView(View view, ViewGroup.LayoutParams layoutParams) { super.addView(view, layoutParams); if (!motionCaptureViewAdded && getManager().getChatHeads().size() > 0) { addContainer(motionCaptureView, true); WindowManager.LayoutParams motionCaptureParams = getOrCreateLayoutParamsForContainer(motionCaptureView); motionCaptureParams.width = 0; motionCaptureParams.height = 0; windowManager.updateViewLayout(motionCaptureView,motionCaptureParams); motionCaptureViewAdded = true; } } @Override public void removeView(View view) { super.removeView(view); if (getManager().getChatHeads().size() == 0) { windowManager.removeViewImmediate(motionCaptureView); motionCaptureViewAdded = false; } } private void removeContainer(View motionCaptureView) { windowManager.removeView(motionCaptureView); } public void destroy() { windowManager.removeViewImmediate(motionCaptureView); windowManager.removeViewImmediate(getFrameLayout()); } protected class MotionCapturingTouchListener implements View.OnTouchListener { @Override public boolean onTouch(View v, MotionEvent event) { event.offsetLocation(getContainerX(v), getContainerY(v)); HostFrameLayout frameLayout = getFrameLayout(); if (frameLayout != null) { return frameLayout.dispatchTouchEvent(event); } else { return false; } } } private class MotionCaptureView extends View { public MotionCaptureView(Context context) { super(context); } } }