/* * Copyright 2015. Appsi Mobile * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.appsimobile.appsii; import android.annotation.TargetApi; import android.content.Context; import android.content.Intent; import android.graphics.PixelFormat; import android.os.Build; import android.util.AttributeSet; import android.view.KeyEvent; import android.view.View; import android.view.ViewGroup; import android.view.ViewParent; import android.view.WindowManager; import android.widget.FrameLayout; import com.appsimobile.appsii.dagger.AppInjector; import javax.inject.Inject; /** * A wrapper around the window-manager, intended to make adding and removing * different components easier. For example this adds the root-layer, that * allows Appsii to animate different floating layers */ public class PopupLayer extends FrameLayout { /** * The last known alpha. So we know if it has changed */ final float mLastAlpha = -1; /** * The window-manager we will be adding stuff to. */ @Inject WindowManager mWindowManager; /** * The default dim amount that is used for Appsii */ float mDefaultDimAlpha; /** * True when the root layer is added */ private boolean mAdded; private View mDimLayerView; private boolean mDimLayerVisible; private int mChildCount; private PopupLayerListener mPopuplayerListener; public PopupLayer(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); } public PopupLayer(Context context, AttributeSet attrs) { super(context, attrs); } public PopupLayer(Context context) { super(context); } public void setDefaultDimAlpha(float pct) { mDefaultDimAlpha = pct; if (mDefaultDimAlpha > 1) mDefaultDimAlpha = 1; if (mDefaultDimAlpha < 0) mDefaultDimAlpha = 0; } public void addPopupChild(View view) { addPopupChild(view, true); } public void addPopupChild(View view, boolean bringToFront) { if (mChildCount == 0) { addLayer(); showDimLayer(); } mChildCount++; LayoutParams lp = (LayoutParams) view.getLayoutParams(); if (lp == null) { lp = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT); } ViewParent vp = view.getParent(); if (vp != null) { ((ViewGroup) vp).removeView(view); } addView(view, lp); setDimLayerAlpha(.5f); if (bringToFront) { view.bringToFront(); } } public void addLayer() { if (!mAdded) { WindowManager.LayoutParams lp = new WindowManager.LayoutParams( WindowManager.LayoutParams.MATCH_PARENT, WindowManager.LayoutParams.MATCH_PARENT, WindowManager.LayoutParams.TYPE_SYSTEM_ALERT, WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH, PixelFormat.TRANSLUCENT); addHardwareAcceleratedFlag(lp); addKitkatFlags(lp); lp.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN; mWindowManager.addView(this, lp); mAdded = true; } else { setVisibility(VISIBLE); if (mPopuplayerListener != null) { mPopuplayerListener.opPopupLayerShown(); } } } private boolean showDimLayer() { if (mDimLayerVisible) return false; mDimLayerVisible = true; if (!AppsiApplication.API19) { mDimLayerView.setVisibility(View.VISIBLE); } return true; } public void setDimLayerAlpha(float newAlpha) { if (mLastAlpha == newAlpha) return; if (AppsiApplication.API19) { WindowManager.LayoutParams params = (WindowManager.LayoutParams) getLayoutParams(); if (params != null) { params.dimAmount = newAlpha * mDefaultDimAlpha; if (mAdded) { mWindowManager.updateViewLayout(this, params); } } } else { float pct = newAlpha * mDefaultDimAlpha; int alpha = (int) (255 * pct); if (alpha > 255) alpha = 255; if (alpha < 0) alpha = 0; alpha = alpha << 24; int color = alpha; mDimLayerView.setBackgroundColor(color); } } @TargetApi(Build.VERSION_CODES.HONEYCOMB) public void addHardwareAcceleratedFlag(WindowManager.LayoutParams params) { params.flags = params.flags | WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED; } @TargetApi(Build.VERSION_CODES.KITKAT) public void addKitkatFlags(WindowManager.LayoutParams params) { if (AppsiApplication.API19) { params.flags = params.flags | WindowManager.LayoutParams.FLAG_DIM_BEHIND | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN | WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION; params.dimAmount = mDefaultDimAlpha; } } public void removePopupChild(View view) { removeView(view); mChildCount--; if (mChildCount <= 0) { removeDimLayer(); removeLayer(); setDimLayerAlpha(1f); mChildCount = 0; } } private boolean removeDimLayer() { if (!mDimLayerVisible) return false; mDimLayerVisible = false; if (!AppsiApplication.API19) { mDimLayerView.setVisibility(View.GONE); } return true; } public void removeLayer() { if (mAdded) { mWindowManager.removeView(this); mAdded = false; } } @Override public boolean onKeyUp(int keyCode, KeyEvent event) { if (event.getKeyCode() == KeyEvent.KEYCODE_BACK || event.getKeyCode() == KeyEvent.KEYCODE_HOME) { Intent i = new Intent(Appsi.ACTION_CLOSE_SIDEBAR); getContext().sendBroadcast(i); forceClose(); return true; } return super.onKeyUp(keyCode, event); } @Override protected void onFinishInflate() { super.onFinishInflate(); AppInjector.inject(this); mDimLayerView = findViewById(R.id.dim_view); if (AppsiApplication.API19) { mDimLayerView.setVisibility(GONE); } setFocusableInTouchMode(true); } public void forceClose() { int count = getChildCount(); for (int i = count - 1; i >= 0; i--) { View v = getChildAt(i); if (v == mDimLayerView) continue; removeView(v); } if (mPopuplayerListener != null) { mPopuplayerListener.onPopupLayerForceClosed(); } removeDimLayer(); removeLayer(); mChildCount = 0; } public void setPopuplayerListener(PopupLayerListener listener) { mPopuplayerListener = listener; } public void onSuspend() { if (mAdded) { mWindowManager.removeView(this); } mAdded = false; } public interface PopupLayerListener { void onPopupLayerForceClosed(); void opPopupLayerHidden() throws PermissionDeniedException; void opPopupLayerShown(); } }