提交 f82d7d73 编写于 作者: G guoshuyu

增加桌面悬浮窗的demo适配

上级 0ffa7eba
......@@ -52,6 +52,7 @@ dependencies {
def androidDependencies = rootProject.ext.androidDependencies
def dataDependencies = rootProject.ext.dataDependencies
annotationProcessor viewDependencies.apt_butterKnife
//debugCompile dataDependencies.leakcanary
compile viewDependencies.butterKnife
compile androidDependencies.recyclerView
compile viewDependencies.DanmakuFlameMaster
......@@ -62,9 +63,8 @@ dependencies {
compile viewDependencies.glideProcessor
compile androidDependencies.support_v4
compile androidDependencies.design
//debugCompile dataDependencies.leakcanary
compile project(':gsyVideoPlayer')
compile project(':gsyVideoPlayer')
//jcenter
//compile "com.shuyu:GSYVideoPlayer:$gsyVideoVersion"
......
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.example.gsyvideoplayer">
<!-- 请求访问网络状态 -->
......@@ -8,7 +9,7 @@
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
 
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
<uses-permission android:name="android.permission.WRITE_SETTINGS" />
<application
......@@ -103,8 +104,21 @@
android:name=".ScrollingActivity"
android:configChanges="orientation|keyboardHidden|screenSize"
android:label="@string/title_activity_scrolling"
android:theme="@style/AppTheme.NoActionBar"
android:screenOrientation="portrait"
android:theme="@style/AppTheme.NoActionBar" />
<activity
android:name=".WindowActivity"
android:configChanges="orientation|keyboardHidden|screenSize"
android:screenOrientation="portrait" />
<activity
android:name=".EmptyActivity"
android:configChanges="orientation|keyboardHidden|screenSize"
android:screenOrientation="portrait" />
<activity
android:name=".utils.floatUtil.FloatActivity"
android:configChanges="orientation|keyboardHidden|screenSize"
android:screenOrientation="portrait" />
</application>
</manifest>
\ No newline at end of file
package com.example.gsyvideoplayer;
import android.content.Intent;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.widget.Button;
import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.OnClick;
public class EmptyActivity extends AppCompatActivity {
@BindView(R.id.jump_other)
Button jumpOther;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_empty);
ButterKnife.bind(this);
}
@OnClick(R.id.jump_other)
public void onViewClicked() {
startActivity(new Intent(this, EmptyActivity.class));
}
}
......@@ -30,7 +30,7 @@ public class MainActivity extends AppCompatActivity {
}
@OnClick({R.id.open_btn, R.id.list_btn, R.id.list_btn_2, R.id.list_detail, R.id.clear_cache, R.id.recycler, R.id.recycler_2, R.id.list_detail_list, R.id.web_detail, R.id.danmaku_video, R.id.fragment_video,
R.id.more_type, R.id.input_type, R.id.open_btn_empty, R.id.open_control, R.id.open_filter, R.id.open_btn_pick, R.id.open_btn_auto, R.id.open_scroll})
R.id.more_type, R.id.input_type, R.id.open_btn_empty, R.id.open_control, R.id.open_filter, R.id.open_btn_pick, R.id.open_btn_auto, R.id.open_scroll, R.id.open_window})
public void onClick(View view) {
switch (view.getId()) {
case R.id.open_btn:
......@@ -101,7 +101,10 @@ public class MainActivity extends AppCompatActivity {
//列表自动播放
JumpUtils.goToScrollDetailPlayer(this);
break;
case R.id.open_window:
//多窗体下的悬浮窗
JumpUtils.goToScrollWindow(this);
break;
case R.id.clear_cache:
//清理缓存
GSYVideoManager.clearAllDefaultCache(MainActivity.this);
......
package com.example.gsyvideoplayer;
import android.content.Intent;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.support.annotation.RequiresApi;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.view.animation.BounceInterpolator;
import android.widget.Button;
import com.example.gsyvideoplayer.utils.floatUtil.FloatWindow;
import com.example.gsyvideoplayer.utils.floatUtil.MoveType;
import com.example.gsyvideoplayer.utils.floatUtil.Screen;
import com.example.gsyvideoplayer.utils.floatUtil.Util;
import com.example.gsyvideoplayer.view.FloatPlayerView;
import com.shuyu.gsyvideoplayer.GSYVideoManager;
import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.OnClick;
/**
* 多窗体下的悬浮窗页面
*/
public class WindowActivity extends AppCompatActivity {
@BindView(R.id.start_window)
Button startWindow;
@BindView(R.id.jump_other)
Button jumpOther;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_window);
ButterKnife.bind(this);
if (Build.VERSION.SDK_INT >= 23) {
if (!Util.hasPermission(this)) {
requestAlertWindowPermission();
}
}
}
@Override
protected void onDestroy() {
super.onDestroy();
GSYVideoManager.instance().releaseMediaPlayer();
/**
* 这里在返回主页的时候销毁了,因为不想和DEMO中其他页面冲突
*/
FloatWindow.destroy();
}
@RequiresApi(api = 23)
private void requestAlertWindowPermission() {
Intent intent = new Intent("android.settings.action.MANAGE_OVERLAY_PERMISSION");
intent.setData(Uri.parse("package:" + getPackageName()));
startActivityForResult(intent, 1);
}
@RequiresApi(api = 23)
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (Build.VERSION.SDK_INT >= 23){
//todo 用23以上编译即可出现canDrawOverlays
if (Util.hasPermission(this)) {
} else {
this.finish();
}
}
}
@OnClick({R.id.start_window, R.id.jump_other})
public void onViewClicked(View view) {
switch (view.getId()) {
case R.id.start_window:
if (FloatWindow.get() != null) {
return;
}
FloatPlayerView floatPlayerView = new FloatPlayerView(getApplicationContext());
FloatWindow
.with(getApplicationContext())
.setView(floatPlayerView)
.setWidth(Screen.width, 0.4f)
.setHeight(Screen.width, 0.4f)
.setX(Screen.width, 0.8f)
.setY(Screen.height, 0.3f)
.setMoveType(MoveType.slide)
.setFilter(false)
.setMoveStyle(500, new BounceInterpolator())
.build();
FloatWindow.get().show();
break;
case R.id.jump_other:
startActivity(new Intent(this, EmptyActivity.class));
break;
}
}
}
......@@ -26,6 +26,7 @@ import com.example.gsyvideoplayer.RecyclerView2Activity;
import com.example.gsyvideoplayer.RecyclerViewActivity;
import com.example.gsyvideoplayer.ScrollingActivity;
import com.example.gsyvideoplayer.WebDetailActivity;
import com.example.gsyvideoplayer.WindowActivity;
/**
* Created by shuyu on 2016/11/11.
......@@ -168,6 +169,16 @@ public class JumpUtils {
activity.startActivity(intent);
}
/**
* 跳转到详情播放
*
* @param activity
*/
public static void goToScrollWindow(Activity activity) {
Intent intent = new Intent(activity, WindowActivity.class);
activity.startActivity(intent);
}
/**
* 跳转到详情播放
*
......
package com.example.gsyvideoplayer.utils.floatUtil;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.provider.Settings;
import android.support.annotation.RequiresApi;
import java.util.ArrayList;
import java.util.List;
/**
* 用于在内部自动申请权限
* https://github.com/yhaolpz
*/
public class FloatActivity extends Activity {
private static List<PermissionListener> mPermissionListenerList;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (Build.VERSION.SDK_INT >= 23){
requestAlertWindowPermission();
}
}
@RequiresApi(api = 23)
private void requestAlertWindowPermission() {
Intent intent = new Intent("android.settings.action.MANAGE_OVERLAY_PERMISSION");
intent.setData(Uri.parse("package:" + getPackageName()));
startActivityForResult(intent, 1);
}
@RequiresApi(api = 23)
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (Build.VERSION.SDK_INT >= 23){
//todo 用23以上编译即可出现canDrawOverlays
if (Util.hasPermission(this)) {
mPermissionListener.onSuccess();
} else {
mPermissionListener.onFail();
}
}
finish();
}
static synchronized void request(Context context, PermissionListener permissionListener) {
if (mPermissionListenerList == null) {
mPermissionListenerList = new ArrayList<>();
mPermissionListener = new PermissionListener() {
@Override
public void onSuccess() {
for (PermissionListener listener : mPermissionListenerList) {
listener.onSuccess();
}
}
@Override
public void onFail() {
for (PermissionListener listener : mPermissionListenerList) {
listener.onFail();
}
}
};
Intent intent = new Intent(context, FloatActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(intent);
}
mPermissionListenerList.add(permissionListener);
}
private static PermissionListener mPermissionListener;
}
package com.example.gsyvideoplayer.utils.floatUtil;
import android.app.Activity;
import android.app.Application;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.os.Handler;
/**
* Created by yhao on 17-12-1.
* 用于控制悬浮窗显示周期
* 使用了三种方法针对返回桌面时隐藏悬浮按钮
* 1.startCount计数,针对back到桌面可以及时隐藏
* 2.监听home键,从而及时隐藏
* 3.resumeCount计时,针对一些只执行onPause不执行onStop的奇葩情况
*/
class FloatLifecycle extends BroadcastReceiver implements Application.ActivityLifecycleCallbacks {
private static final String SYSTEM_DIALOG_REASON_KEY = "reason";
private static final String SYSTEM_DIALOG_REASON_HOME_KEY = "homekey";
private static final long delay = 300;
private Handler mHandler;
private Class[] activities;
private boolean showFlag;
private int startCount;
private int resumeCount;
private boolean appBackground;
private LifecycleListener mLifecycleListener;
FloatLifecycle(Context applicationContext, boolean showFlag, Class[] activities, LifecycleListener lifecycleListener) {
this.showFlag = showFlag;
this.activities = activities;
mLifecycleListener = lifecycleListener;
mHandler = new Handler();
((Application) applicationContext).registerActivityLifecycleCallbacks(this);
applicationContext.registerReceiver(this, new IntentFilter(Intent.ACTION_CLOSE_SYSTEM_DIALOGS));
}
private boolean needShow(Activity activity) {
if (activities == null) {
return true;
}
for (Class a : activities) {
if (a.isInstance(activity)) {
return showFlag;
}
}
return !showFlag;
}
@Override
public void onActivityResumed(Activity activity) {
resumeCount++;
if (needShow(activity)) {
mLifecycleListener.onShow();
} else {
//mLifecycleListener.onHide();
}
if (appBackground) {
appBackground = false;
}
}
@Override
public void onActivityPaused(Activity activity) {
resumeCount--;
mHandler.postDelayed(new Runnable() {
@Override
public void run() {
if (resumeCount == 0) {
appBackground = true;
//mLifecycleListener.onPostHide();
}
}
}, delay);
}
@Override
public void onActivityStarted(Activity activity) {
startCount++;
}
@Override
public void onActivityStopped(Activity activity) {
startCount--;
if (startCount == 0) {
//mLifecycleListener.onHide();
}
}
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (action != null && action.equals(Intent.ACTION_CLOSE_SYSTEM_DIALOGS)) {
String reason = intent.getStringExtra(SYSTEM_DIALOG_REASON_KEY);
if (SYSTEM_DIALOG_REASON_HOME_KEY.equals(reason)) {
//mLifecycleListener.onHide();
}
}
}
@Override
public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
}
@Override
public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
}
@Override
public void onActivityDestroyed(Activity activity) {
}
}
package com.example.gsyvideoplayer.utils.floatUtil;
import android.content.Context;
import android.graphics.PixelFormat;
import android.view.View;
import android.view.WindowManager;
/**
* Created by yhao on 17-11-14.
* 7.1及以上需申请权限
*/
class FloatPhone extends FloatView {
private final Context mContext;
private final WindowManager mWindowManager;
private final WindowManager.LayoutParams mLayoutParams;
private View mView;
private int mX, mY;
FloatPhone(Context applicationContext) {
mContext = applicationContext;
mWindowManager = (WindowManager) applicationContext.getSystemService(Context.WINDOW_SERVICE);
mLayoutParams = new WindowManager.LayoutParams();
}
@Override
public void setSize(int width, int height) {
mLayoutParams.width = width;
mLayoutParams.height = height;
}
@Override
public void setView(View view) {
mLayoutParams.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
| WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
mLayoutParams.type = WindowManager.LayoutParams.TYPE_PHONE;
mLayoutParams.windowAnimations = 0;
mView = view;
}
@Override
public void setGravity(int gravity, int xOffset, int yOffset) {
mLayoutParams.gravity = gravity;
mLayoutParams.x = mX = xOffset;
mLayoutParams.y = mY = yOffset;
}
@Override
public void init() {
if (Util.hasPermission(mContext)) {
mLayoutParams.format = PixelFormat.RGBA_8888;
mWindowManager.addView(mView, mLayoutParams);
} else {
FloatActivity.request(mContext, new PermissionListener() {
@Override
public void onSuccess() {
mLayoutParams.format = PixelFormat.RGBA_8888;
mWindowManager.addView(mView, mLayoutParams);
}
@Override
public void onFail() {
}
});
}
}
@Override
public void dismiss() {
mWindowManager.removeView(mView);
}
@Override
public void updateXY(int x, int y) {
mLayoutParams.x = mX = x;
mLayoutParams.y = mY = y;
mWindowManager.updateViewLayout(mView, mLayoutParams);
}
@Override
void updateX(int x) {
mLayoutParams.x = mX = x;
mWindowManager.updateViewLayout(mView, mLayoutParams);
}
@Override
void updateY(int y) {
mLayoutParams.y = mY = y;
mWindowManager.updateViewLayout(mView, mLayoutParams);
}
@Override
int getX() {
return mX;
}
@Override
int getY() {
return mY;
}
}
package com.example.gsyvideoplayer.utils.floatUtil;
import android.content.Context;
import android.view.View;
import android.view.WindowManager;
import android.widget.Toast;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
/**
* 自定义 toast 方式,无需申请权限
*/
class FloatToast extends FloatView {
private Toast toast;
private Object mTN;
private Method show;
private Method hide;
private int mWidth;
private int mHeight;
FloatToast(Context applicationContext) {
toast = new Toast(applicationContext);
}
@Override
public void setSize(int width, int height) {
mWidth = width;
mHeight = height;
}
@Override
public void setView(View view) {
toast.setView(view);
initTN();
}
@Override
public void setGravity(int gravity, int xOffset, int yOffset) {
toast.setGravity(gravity, xOffset, yOffset);
}
@Override
public void init() {
try {
show.invoke(mTN);
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public void dismiss() {
try {
hide.invoke(mTN);
} catch (Exception e) {
e.printStackTrace();
}
}
private void initTN() {
try {
Field tnField = toast.getClass().getDeclaredField("mTN");
tnField.setAccessible(true);
mTN = tnField.get(toast);
show = mTN.getClass().getMethod("show");
hide = mTN.getClass().getMethod("hide");
Field tnParamsField = mTN.getClass().getDeclaredField("mParams");
tnParamsField.setAccessible(true);
WindowManager.LayoutParams params = (WindowManager.LayoutParams) tnParamsField.get(mTN);
params.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
| WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
params.width = mWidth;
params.height = mHeight;
params.windowAnimations = 0;
Field tnNextViewField = mTN.getClass().getDeclaredField("mNextView");
tnNextViewField.setAccessible(true);
tnNextViewField.set(mTN, toast.getView());
} catch (Exception e) {
e.printStackTrace();
}
}
}
package com.example.gsyvideoplayer.utils.floatUtil;
import android.view.View;
/**
* Created by yhao on 17-11-14.
* https://github.com/yhaolpz
*/
abstract class FloatView {
abstract void setSize(int width, int height);
abstract void setView(View view);
abstract void setGravity(int gravity, int xOffset, int yOffset);
abstract void init();
abstract void dismiss();
void updateXY(int x, int y) {
}
void updateX(int x) {
}
void updateY(int y) {
}
int getX() {
return 0;
}
int getY() {
return 0;
}
}
package com.example.gsyvideoplayer.utils.floatUtil;
import android.animation.TimeInterpolator;
import android.content.Context;
import android.support.annotation.LayoutRes;
import android.support.annotation.MainThread;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
import java.util.HashMap;
import java.util.Map;
/**
* Created by yhao on 2017/12/22.
* https://github.com/yhaolpz
*/
public class FloatWindow {
private FloatWindow() {
}
private static final String mDefaultTag = "default_float_window_tag";
private static Map<String, IFloatWindow> mFloatWindowMap;
public static IFloatWindow get() {
return get(mDefaultTag);
}
public static IFloatWindow get(@NonNull String tag) {
return mFloatWindowMap == null ? null : mFloatWindowMap.get(tag);
}
private static B mBuilder = null;
@MainThread
public static B with(@NonNull Context applicationContext) {
return mBuilder = new B(applicationContext);
}
public static void destroy() {
destroy(mDefaultTag);
}
public static void destroy(String tag) {
if (mFloatWindowMap == null || !mFloatWindowMap.containsKey(tag)) {
return;
}
mFloatWindowMap.get(tag).dismiss();
mFloatWindowMap.remove(tag);
}
public static class B {
Context mApplicationContext;
View mView;
private int mLayoutId;
int mWidth = ViewGroup.LayoutParams.WRAP_CONTENT;
int mHeight = ViewGroup.LayoutParams.WRAP_CONTENT;
int gravity = Gravity.TOP | Gravity.START;
int xOffset;
int yOffset;
boolean mShow = true;
Class[] mActivities;
int mMoveType = MoveType.fixed;
long mDuration = 300;
TimeInterpolator mInterpolator;
private String mTag = mDefaultTag;
private B() {
}
B(Context applicationContext) {
mApplicationContext = applicationContext;
}
public B setView(@NonNull View view) {
mView = view;
return this;
}
public B setView(@LayoutRes int layoutId) {
mLayoutId = layoutId;
return this;
}
public B setWidth(int width) {
mWidth = width;
return this;
}
public B setHeight(int height) {
mHeight = height;
return this;
}
public B setWidth(@Screen.screenType int screenType, float ratio) {
mWidth = (int) ((screenType == Screen.width ?
Util.getScreenWidth(mApplicationContext) :
Util.getScreenHeight(mApplicationContext)) * ratio);
return this;
}
public B setHeight(@Screen.screenType int screenType, float ratio) {
mHeight = (int) ((screenType == Screen.width ?
Util.getScreenWidth(mApplicationContext) :
Util.getScreenHeight(mApplicationContext)) * ratio);
return this;
}
public B setX(int x) {
xOffset = x;
return this;
}
public B setY(int y) {
yOffset = y;
return this;
}
public B setX(@Screen.screenType int screenType, float ratio) {
xOffset = (int) ((screenType == Screen.width ?
Util.getScreenWidth(mApplicationContext) :
Util.getScreenHeight(mApplicationContext)) * ratio);
return this;
}
public B setY(@Screen.screenType int screenType, float ratio) {
yOffset = (int) ((screenType == Screen.width ?
Util.getScreenWidth(mApplicationContext) :
Util.getScreenHeight(mApplicationContext)) * ratio);
return this;
}
/**
* 设置 Activity 过滤器,用于指定在哪些界面显示悬浮窗,默认全部界面都显示
*
* @param show  过滤类型,子类类型也会生效
* @param activities  过滤界面
*/
public B setFilter(boolean show, @NonNull Class... activities) {
mShow = show;
mActivities = activities;
return this;
}
public B setMoveType(@MoveType.MOVE_TYPE int moveType) {
mMoveType = moveType;
return this;
}
public B setMoveStyle(long duration, @Nullable TimeInterpolator interpolator) {
mDuration = duration;
mInterpolator = interpolator;
return this;
}
public B setTag(@NonNull String tag) {
mTag = tag;
return this;
}
public void build() {
if (mFloatWindowMap == null) {
mFloatWindowMap = new HashMap<>();
}
if (mFloatWindowMap.containsKey(mTag)) {
throw new IllegalArgumentException("FloatWindow of this tag has been added, Please set a new tag for the new FloatWindow");
}
if (mView == null && mLayoutId == 0) {
throw new IllegalArgumentException("View has not been set!");
}
if (mView == null) {
mView = Util.inflate(mApplicationContext, mLayoutId);
}
IFloatWindow floatWindowImpl = new IFloatWindowImpl(this);
mFloatWindowMap.put(mTag, floatWindowImpl);
}
}
}
package com.example.gsyvideoplayer.utils.floatUtil;
import android.view.View;
/**
* Created by yhao on 2017/12/22.
* https://github.com/yhaolpz
*/
public abstract class IFloatWindow {
public abstract void show();
public abstract void hide();
public abstract int getX();
public abstract int getY();
public abstract void updateX(int x);
public abstract void updateX(@Screen.screenType int screenType,float ratio);
public abstract void updateY(int y);
public abstract void updateY(@Screen.screenType int screenType,float ratio);
public abstract View getView();
abstract void dismiss();
}
package com.example.gsyvideoplayer.utils.floatUtil;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ObjectAnimator;
import android.animation.PropertyValuesHolder;
import android.animation.TimeInterpolator;
import android.animation.ValueAnimator;
import android.os.Build;
import android.view.MotionEvent;
import android.view.View;
import android.view.animation.DecelerateInterpolator;
/**
* Created by yhao on 2017/12/22.
* https://github.com/yhaolpz
*/
public class IFloatWindowImpl extends IFloatWindow {
private FloatWindow.B mB;
private FloatView mFloatView;
private FloatLifecycle mFloatLifecycle;
private boolean isShow;
private boolean once = true;
private ValueAnimator mAnimator;
private TimeInterpolator mDecelerateInterpolator;
private IFloatWindowImpl() {
}
IFloatWindowImpl(FloatWindow.B b) {
mB = b;
if (mB.mMoveType == MoveType.fixed) {
if (Build.VERSION.SDK_INT >=25) {
mFloatView = new FloatPhone(b.mApplicationContext);
} else {
mFloatView = new FloatToast(b.mApplicationContext);
}
} else {
mFloatView = new FloatPhone(b.mApplicationContext);
initTouchEvent();
}
mFloatView.setSize(mB.mWidth, mB.mHeight);
mFloatView.setGravity(mB.gravity, mB.xOffset, mB.yOffset);
mFloatView.setView(mB.mView);
mFloatLifecycle = new FloatLifecycle(mB.mApplicationContext, mB.mShow, mB.mActivities, new LifecycleListener() {
@Override
public void onShow() {
show();
}
@Override
public void onHide() {
hide();
}
@Override
public void onPostHide() {
postHide();
}
});
}
@Override
public void show() {
if (once) {
mFloatView.init();
once = false;
isShow = true;
} else {
if (isShow) return;
getView().setVisibility(View.VISIBLE);
isShow = true;
}
}
@Override
public void hide() {
if (once || !isShow) return;
getView().setVisibility(View.INVISIBLE);
isShow = false;
}
@Override
void dismiss() {
mFloatView.dismiss();
isShow = false;
}
@Override
public void updateX(int x) {
checkMoveType();
mB.xOffset = x;
mFloatView.updateX(x);
}
@Override
public void updateY(int y) {
checkMoveType();
mB.yOffset = y;
mFloatView.updateY(y);
}
@Override
public void updateX(int screenType, float ratio) {
checkMoveType();
mB.xOffset = (int) ((screenType == Screen.width ?
Util.getScreenWidth(mB.mApplicationContext) :
Util.getScreenHeight(mB.mApplicationContext)) * ratio);
mFloatView.updateX(mB.xOffset);
}
@Override
public void updateY(int screenType, float ratio) {
checkMoveType();
mB.yOffset = (int) ((screenType == Screen.width ?
Util.getScreenWidth(mB.mApplicationContext) :
Util.getScreenHeight(mB.mApplicationContext)) * ratio);
mFloatView.updateY(mB.yOffset);
}
@Override
public int getX() {
return mFloatView.getX();
}
@Override
public int getY() {
return mFloatView.getY();
}
@Override
public View getView() {
return mB.mView;
}
void postHide() {
if (once || !isShow) return;
getView().post(new Runnable() {
@Override
public void run() {
getView().setVisibility(View.INVISIBLE);
}
});
isShow = false;
}
private void checkMoveType() {
if (mB.mMoveType == MoveType.fixed) {
throw new IllegalArgumentException("FloatWindow of this tag is not allowed to move!");
}
}
private void initTouchEvent() {
switch (mB.mMoveType) {
case MoveType.free:
break;
default:
getView().setOnTouchListener(new View.OnTouchListener() {
float lastX, lastY, changeX, changeY;
int newX, newY;
@Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
lastX = event.getRawX();
lastY = event.getRawY();
cancelAnimator();
break;
case MotionEvent.ACTION_MOVE:
changeX = event.getRawX() - lastX;
changeY = event.getRawY() - lastY;
newX = (int) (mFloatView.getX() + changeX);
newY = (int) (mFloatView.getY() + changeY);
mFloatView.updateXY(newX, newY);
lastX = event.getRawX();
lastY = event.getRawY();
break;
case MotionEvent.ACTION_UP:
switch (mB.mMoveType) {
case MoveType.slide:
int startX = mFloatView.getX();
int endX = (startX * 2 + v.getWidth() >
Util.getScreenWidth(mB.mApplicationContext)) ?
Util.getScreenWidth(mB.mApplicationContext) - v.getWidth() : 0;
mAnimator = ObjectAnimator.ofInt(startX, endX);
mAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
int x = (int) animation.getAnimatedValue();
mFloatView.updateX(x);
}
});
startAnimator();
break;
case MoveType.back:
PropertyValuesHolder pvhX = PropertyValuesHolder.ofInt("x", mFloatView.getX(), mB.xOffset);
PropertyValuesHolder pvhY = PropertyValuesHolder.ofInt("y", mFloatView.getY(), mB.yOffset);
mAnimator = ObjectAnimator.ofPropertyValuesHolder(pvhX, pvhY);
mAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
int x = (int) animation.getAnimatedValue("x");
int y = (int) animation.getAnimatedValue("y");
mFloatView.updateXY(x, y);
}
});
startAnimator();
break;
}
break;
}
return false;
}
});
}
}
private void startAnimator() {
if (mB.mInterpolator == null) {
if (mDecelerateInterpolator == null) {
mDecelerateInterpolator = new DecelerateInterpolator();
}
mB.mInterpolator = mDecelerateInterpolator;
}
mAnimator.setInterpolator(mB.mInterpolator);
mAnimator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
mAnimator.removeAllUpdateListeners();
mAnimator.removeAllListeners();
mAnimator = null;
}
});
mAnimator.setDuration(mB.mDuration).start();
}
private void cancelAnimator() {
if (mAnimator != null && mAnimator.isRunning()) {
mAnimator.cancel();
}
}
}
package com.example.gsyvideoplayer.utils.floatUtil;
/**
* Created by yhao on 2017/12/22.
* https://github.com/yhaolpz
*/
interface LifecycleListener {
void onShow();
void onHide();
void onPostHide();
}
package com.example.gsyvideoplayer.utils.floatUtil;
import android.support.annotation.IntDef;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
/**
* Created by yhao on 2017/12/22.
* https://github.com/yhaolpz
*/
public class MoveType {
static final int fixed = 0;
public static final int free = 1;
public static final int active = 2;
public static final int slide = 3;
public static final int back = 4;
@IntDef({fixed, free, active, slide, back})
@Retention(RetentionPolicy.SOURCE)
@interface MOVE_TYPE {
}
}
package com.example.gsyvideoplayer.utils.floatUtil;
/**
* Created by yhao on 2017/11/14.
* https://github.com/yhaolpz
*/
interface PermissionListener {
void onSuccess();
void onFail();
}
package com.example.gsyvideoplayer.utils.floatUtil;
import android.support.annotation.IntDef;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
/**
* Created by yhao on 2017/12/23.
* https://github.com/yhaolpz
*/
public class Screen {
public static final int width = 0;
public static final int height = 1;
@IntDef({width, height})
@Retention(RetentionPolicy.SOURCE)
@interface screenType {
}
}
package com.example.gsyvideoplayer.utils.floatUtil;
import android.content.Context;
import android.graphics.Point;
import android.provider.Settings;
import android.view.LayoutInflater;
import android.view.View;
import android.view.WindowManager;
import java.lang.reflect.Method;
/**
* Created by yhao on 2017/12/22.
* https://github.com/yhaolpz
*/
public class Util {
static View inflate(Context applicationContext, int layoutId) {
LayoutInflater inflate = (LayoutInflater) applicationContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
return inflate.inflate(layoutId, null);
}
public static boolean hasPermission(Context context) {
Boolean result;
try {
Class clazz = Settings.class;
Method canDrawOverlays = clazz.getDeclaredMethod("canDrawOverlays", Context.class);
result = (Boolean) canDrawOverlays.invoke(null, context);
} catch (Exception e) {
result = false;
}
return result;
}
private static Point sPoint;
static int getScreenWidth(Context context) {
if (sPoint == null) {
sPoint = new Point();
WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
wm.getDefaultDisplay().getSize(sPoint);
}
return sPoint.x;
}
static int getScreenHeight(Context context) {
if (sPoint == null) {
sPoint = new Point();
WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
wm.getDefaultDisplay().getSize(sPoint);
}
return sPoint.y;
}
}
package com.example.gsyvideoplayer.video;
import android.content.Context;
import android.media.AudioManager;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;
import com.example.gsyvideoplayer.R;
import com.shuyu.gsyvideoplayer.GSYVideoManager;
import com.shuyu.gsyvideoplayer.utils.Debuger;
import com.shuyu.gsyvideoplayer.video.StandardGSYVideoPlayer;
import java.util.Timer;
import java.util.TimerTask;
import static com.shuyu.gsyvideoplayer.utils.CommonUtil.hideNavKey;
/**
* 多窗体下的悬浮窗页面支持Video
* Created by shuyu on 2017/12/25.
*/
public class FloatingVideo extends StandardGSYVideoPlayer {
protected DismissControlViewTimerTask mDismissControlViewTimerTask;
/**
* 1.5.0开始加入,如果需要不同布局区分功能,需要重载
*/
public FloatingVideo(Context context, Boolean fullFlag) {
super(context, fullFlag);
}
public FloatingVideo(Context context) {
super(context);
}
public FloatingVideo(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
protected void init(Context context) {
if (getActivityContext() != null) {
this.mContext = getActivityContext();
} else {
this.mContext = context;
}
initInflate(mContext);
mTextureViewContainer = (ViewGroup) findViewById(R.id.surface_container);
mStartButton = findViewById(R.id.start);
if (isInEditMode())
return;
mScreenWidth = getActivityContext().getResources().getDisplayMetrics().widthPixels;
mScreenHeight = getActivityContext().getResources().getDisplayMetrics().heightPixels;
mAudioManager = (AudioManager) getActivityContext().getApplicationContext().getSystemService(Context.AUDIO_SERVICE);
mStartButton = findViewById(com.shuyu.gsyvideoplayer.R.id.start);
mStartButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
clickStartIcon();
}
});
}
@Override
public int getLayoutId() {
return R.layout.layout_floating_video;
}
@Override
protected void startPrepare() {
if (GSYVideoManager.instance().listener() != null) {
GSYVideoManager.instance().listener().onCompletion();
}
GSYVideoManager.instance().setListener(this);
GSYVideoManager.instance().setPlayTag(mPlayTag);
GSYVideoManager.instance().setPlayPosition(mPlayPosition);
mAudioManager.requestAudioFocus(onAudioFocusChangeListener, AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN_TRANSIENT);
//((Activity) getActivityContext()).getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
mBackUpPlayingBufferState = -1;
GSYVideoManager.instance().prepare(mUrl, mMapHeadData, mLooping, mSpeed);
setStateAndUi(CURRENT_STATE_PREPAREING);
}
@Override
public void onAutoCompletion() {
setStateAndUi(CURRENT_STATE_AUTO_COMPLETE);
mSaveChangeViewTIme = 0;
if (mTextureViewContainer.getChildCount() > 0) {
mTextureViewContainer.removeAllViews();
}
if (!mIfCurrentIsFullscreen)
GSYVideoManager.instance().setLastListener(null);
mAudioManager.abandonAudioFocus(onAudioFocusChangeListener);
//((Activity) getActivityContext()).getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
releaseNetWorkState();
if (mVideoAllCallBack != null && isCurrentMediaListener()) {
Debuger.printfLog("onAutoComplete");
mVideoAllCallBack.onAutoComplete(mOriginUrl, mTitle, this);
}
}
@Override
public void onCompletion() {
//make me normal first
setStateAndUi(CURRENT_STATE_NORMAL);
mSaveChangeViewTIme = 0;
if (mTextureViewContainer.getChildCount() > 0) {
mTextureViewContainer.removeAllViews();
}
if (!mIfCurrentIsFullscreen) {
GSYVideoManager.instance().setListener(null);
GSYVideoManager.instance().setLastListener(null);
}
GSYVideoManager.instance().setCurrentVideoHeight(0);
GSYVideoManager.instance().setCurrentVideoWidth(0);
mAudioManager.abandonAudioFocus(onAudioFocusChangeListener);
//((Activity) getActivityContext()).getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
releaseNetWorkState();
}
@Override
protected Context getActivityContext() {
return getContext();
}
@Override
protected void startDismissControlViewTimer() {
cancelDismissControlViewTimer();
mDismissControlViewTimer = new Timer();
mDismissControlViewTimerTask = new DismissControlViewTimerTask();
mDismissControlViewTimer.schedule(mDismissControlViewTimerTask, mDismissControlTime);
}
@Override
protected void cancelDismissControlViewTimer() {
if (mDismissControlViewTimer != null) {
mDismissControlViewTimer.cancel();
mDismissControlViewTimer = null;
}
if (mDismissControlViewTimerTask != null) {
mDismissControlViewTimerTask.cancel();
mDismissControlViewTimerTask = null;
}
}
private class DismissControlViewTimerTask extends TimerTask {
@Override
public void run() {
if (mCurrentState != CURRENT_STATE_NORMAL
&& mCurrentState != CURRENT_STATE_ERROR
&& mCurrentState != CURRENT_STATE_AUTO_COMPLETE) {
if (getActivityContext() != null) {
FloatingVideo.this.post(new Runnable() {
@Override
public void run() {
hideAllWidget();
setViewShowState(mLockScreen, GONE);
if (mHideKey && mIfCurrentIsFullscreen && mShowVKey) {
hideNavKey(mContext);
}
}
});
}
}
}
}
}
package com.example.gsyvideoplayer.view;
import android.content.Context;
import android.graphics.Color;
import android.util.AttributeSet;
import android.view.Gravity;
import android.view.ViewGroup;
import android.widget.FrameLayout;
import com.example.gsyvideoplayer.video.FloatingVideo;
import com.shuyu.gsyvideoplayer.video.base.GSYVideoPlayer;
/**
* Created by guoshuyu on 2017/12/25.
*/
public class FloatPlayerView extends FrameLayout {
FloatingVideo videoPlayer;
public FloatPlayerView(Context context) {
super(context);
init();
}
public FloatPlayerView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public FloatPlayerView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
private void init() {
videoPlayer = new FloatingVideo(getContext());
LayoutParams layoutParams = new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
layoutParams.gravity = Gravity.CENTER;
addView(videoPlayer, layoutParams);
String source1 = "http://9890.vod.myqcloud.com/9890_4e292f9a3dd011e6b4078980237cc3d3.f20.mp4";
videoPlayer.setUp(source1, true, "测试视频");
//增加封面
/*ImageView imageView = new ImageView(getContext());
imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
imageView.setImageResource(R.mipmap.xxx1);
videoPlayer.setThumbImageView(imageView);*/
//是否可以滑动调整
videoPlayer.setIsTouchWiget(false);
}
public void onPause() {
videoPlayer.onVideoPause();
}
public void onResume() {
videoPlayer.onVideoResume();
}
public void onBackPressed() {
//释放所有
videoPlayer.setStandardVideoAllCallBack(null);
GSYVideoPlayer.releaseAllVideos();
}
}
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<Button
android:id="@+id/jump_other"
android:layout_width="120dp"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:text="跳转其他页面" />
</LinearLayout>
......@@ -143,6 +143,13 @@
android:layout_marginTop="20dp"
android:text="联动detail" />
<Button
android:id="@+id/open_window"
android:layout_width="120dp"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:text="悬浮窗口" />
<Button
android:id="@+id/clear_cache"
android:layout_width="120dp"
......
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<Button
android:id="@+id/start_window"
android:layout_width="120dp"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:text="启动悬浮窗口" />
<Button
android:id="@+id/jump_other"
android:layout_width="120dp"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:text="跳转其他页面" />
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="10dp"
android:textSize="15sp"
android:text="返回到桌面,或者点击跳转其他页面均可以存在,demo这里在返回主页Main的时候销毁,因为不想和DEMO中其他页面冲突" />
</LinearLayout>
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/activity_play"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#000000">
<com.example.gsyvideoplayer.video.FloatingVideo
android:id="@+id/video_player"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_centerInParent="true" />
</RelativeLayout>
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@android:color/black">
<FrameLayout
android:id="@+id/surface_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center">
</FrameLayout>
<moe.codeest.enviews.ENPlayView
android:id="@+id/start"
android:layout_width="35dp"
android:layout_height="35dp"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
android:layout_gravity="center_vertical" />
</RelativeLayout>
......@@ -20,6 +20,7 @@ ext {
DanmakuFlameMaster = '0.6.4'
transitionseverywhere = '1.7.0'
floatWindow = '1.0.6'
//DataLibraries
videocache = '2.1.1'
......@@ -53,7 +54,8 @@ ext {
ndkbitmap_armv5 : "com.github.ctiao:ndkbitmap-armv5:${DanmakuFlameMaster}",
ndkbitmap_x86 : "com.github.ctiao:ndkbitmap-x86:${DanmakuFlameMaster}",
glide : "com.github.bumptech.glide:glide:${imageLoader}",
glideProcessor : "com.github.bumptech.glide:compiler:${imageLoader}"
glideProcessor : "com.github.bumptech.glide:compiler:${imageLoader}",
floatWindow : "com.github.yhaolpz:FloatWindow:${floatWindow}",
]
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册