package com.android.launcher3.floatingwindow; import android.content.Context; import android.os.Handler; import android.os.Looper; import android.util.Log; import android.view.Gravity; import android.view.View; import android.view.WindowManager; import androidx.annotation.CallSuper; import androidx.annotation.IdRes; import androidx.annotation.LayoutRes; import static android.content.Context.WINDOW_SERVICE; /** * Author: roczheng * Date: 2020/7/6 * Time: 11:51 * Description: */ public abstract class AbsFloatBase { public static final String TAG = "AbsFloatBase"; static final int FULLSCREEN_TOUCHABLE = 1; static final int FULLSCREEN_NOT_TOUCHABLE = 2; static final int WRAP_CONTENT_TOUCHABLE = 3; static final int WRAP_CONTENT_NOT_TOUCHABLE = 4; WindowManager.LayoutParams mLayoutParams; View mInflate; Context mContext; WindowManager mWindowManager; private boolean mAdded; //设置隐藏时是否是INVISIBLE private boolean mInvisibleNeed = false; private boolean mRequestFocus = false; int mGravity = Gravity.CENTER_HORIZONTAL | Gravity.CENTER_VERTICAL; int mViewMode = WRAP_CONTENT_NOT_TOUCHABLE; Handler mHandler = new Handler(Looper.getMainLooper()); public AbsFloatBase(Context context) { mContext = context; create(); } /** * 设置隐藏View的方式是否为Invisible,默认为Gone * * @param invisibleNeed 是否是Invisible */ public void setInvisibleNeed(boolean invisibleNeed) { mInvisibleNeed = invisibleNeed; } /** * 悬浮窗是否需要获取焦点,通常获取焦点后,悬浮窗可以和软键盘发生交互,被覆盖的应用失去焦点。 * 例如:游戏将失去背景音乐 * * @param requestFocus */ public void requestFocus(boolean requestFocus) { mRequestFocus = requestFocus; } @CallSuper public void create() { mWindowManager = (WindowManager) mContext.getApplicationContext().getSystemService(WINDOW_SERVICE); } @CallSuper public synchronized void show() { if (mInflate == null) throw new IllegalStateException("FloatView can not be null"); if (mAdded) { mInflate.setVisibility(View.VISIBLE); return; } getLayoutParam(mViewMode); mInflate.setVisibility(View.VISIBLE); try { mWindowManager.addView(mInflate, mLayoutParams); mAdded = true; } catch (Exception e) { Log.e(TAG, "添加悬浮窗失败!!!!!!请检查悬浮窗权限"); // Toast.makeText(mContext, "添加悬浮窗失败!!!!!!请检查悬浮窗权限", Toast.LENGTH_SHORT).show(); onAddWindowFailed(e); } } @CallSuper public void hide() { if (mInflate != null) { mInflate.setVisibility(View.INVISIBLE); } } @CallSuper public void gone() { if (mInflate != null) { mInflate.setVisibility(View.GONE); } } @CallSuper public void remove() { if (mInflate != null && mWindowManager != null) { if (mInflate.isAttachedToWindow()) { mWindowManager.removeView(mInflate); } mAdded = false; } if (mHandler != null) { mHandler.removeCallbacksAndMessages(null); } } @CallSuper protected View inflate(@LayoutRes int layout) { mInflate = View.inflate(mContext, layout, null); return mInflate; } protected abstract void onAddWindowFailed(Exception e); @SuppressWarnings("unchecked") protected <T extends View> T findView(@IdRes int id) { if (mInflate != null) { return (T) mInflate.findViewById(id); } return null; } /** * 获取悬浮窗LayoutParam * * @param mode */ protected void getLayoutParam(int mode) { switch (mode) { case FULLSCREEN_TOUCHABLE: mLayoutParams = FloatWindowParamManager.getFloatLayoutParam(true, true); break; case FULLSCREEN_NOT_TOUCHABLE: mLayoutParams = FloatWindowParamManager.getFloatLayoutParam(true, false); break; case WRAP_CONTENT_NOT_TOUCHABLE: mLayoutParams = FloatWindowParamManager.getFloatLayoutParam(false, false); break; case WRAP_CONTENT_TOUCHABLE: mLayoutParams = FloatWindowParamManager.getFloatLayoutParam(false, true); break; } if (mRequestFocus) { mLayoutParams.flags = mLayoutParams.flags & ~WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE; } mLayoutParams.gravity = mGravity; } /** * 获取可见性 * * @return */ public boolean getVisibility() { if (mInflate != null && mInflate.getVisibility() == View.VISIBLE) { return true; } else { return false; } } /** * 改变可见性 */ public void toggleVisibility() { if (mInflate != null) { if (getVisibility()) { if (mInvisibleNeed) { hide(); } else { gone(); } } else { show(); } } } }