update 封装base库;集成flowwindow库;悬浮窗功能;赞助和分享;集成企微sdk;界面更新;添加待办修复;滚动手势优化;建群达到上限检查;兼容减号和括号搜索;应用保活;其他已知缺陷修复
1
floatwindow/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
/build
|
||||
38
floatwindow/build.gradle
Normal file
@@ -0,0 +1,38 @@
|
||||
apply plugin: 'com.android.library'
|
||||
apply plugin: 'kotlin-android'
|
||||
apply plugin: 'kotlin-android-extensions'
|
||||
|
||||
android {
|
||||
compileSdkVersion 30
|
||||
|
||||
defaultConfig {
|
||||
minSdkVersion 24
|
||||
targetSdkVersion 30
|
||||
versionCode 1
|
||||
versionName "1.0"
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
release {
|
||||
minifyEnabled true
|
||||
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
|
||||
}
|
||||
}
|
||||
compileOptions {
|
||||
sourceCompatibility JavaVersion.VERSION_1_8
|
||||
targetCompatibility JavaVersion.VERSION_1_8
|
||||
}
|
||||
kotlinOptions {
|
||||
jvmTarget = '1.8'
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
api "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
|
||||
api 'androidx.core:core-ktx:1.3.2'
|
||||
api 'androidx.appcompat:appcompat:1.3.1'
|
||||
api 'com.google.android.material:material:1.4.0'
|
||||
|
||||
//工具集
|
||||
api 'com.blankj:utilcodex:1.31.0'
|
||||
}
|
||||
21
floatwindow/proguard-rules.pro
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
# Add project specific ProGuard rules here.
|
||||
# You can control the set of applied configuration files using the
|
||||
# proguardFiles setting in build.gradle.
|
||||
#
|
||||
# For more details, see
|
||||
# http://developer.android.com/guide/developing/tools/proguard.html
|
||||
|
||||
# If your project uses WebView with JS, uncomment the following
|
||||
# and specify the fully qualified class name to the JavaScript interface
|
||||
# class:
|
||||
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
|
||||
# public *;
|
||||
#}
|
||||
|
||||
# Uncomment this to preserve the line number information for
|
||||
# debugging stack traces.
|
||||
#-keepattributes SourceFile,LineNumberTable
|
||||
|
||||
# If you keep the line number information, uncomment this to
|
||||
# hide the original source file name.
|
||||
#-renamesourcefileattribute SourceFile
|
||||
13
floatwindow/src/main/AndroidManifest.xml
Normal file
@@ -0,0 +1,13 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="org.yameida.floatwindow">
|
||||
|
||||
<uses-permission android:name="android.permission.SYSTEM_OVERLAY_WINDOW" />
|
||||
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
|
||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
|
||||
|
||||
<application android:label="@string/app_name">
|
||||
<service android:name=".DefaultFloatService" />
|
||||
</application>
|
||||
|
||||
</manifest>
|
||||
@@ -0,0 +1,706 @@
|
||||
package org.yameida.floatwindow;
|
||||
|
||||
import android.animation.Animator;
|
||||
import android.animation.ValueAnimator;
|
||||
import android.app.Service;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.content.res.Configuration;
|
||||
import android.graphics.PixelFormat;
|
||||
import android.os.Build;
|
||||
import android.os.CountDownTimer;
|
||||
import android.os.Handler;
|
||||
import android.os.IBinder;
|
||||
import android.os.Looper;
|
||||
import android.provider.Settings;
|
||||
import android.view.Gravity;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.view.WindowManager;
|
||||
import android.view.animation.Interpolator;
|
||||
import android.view.animation.LinearInterpolator;
|
||||
|
||||
import com.blankj.utilcode.util.BarUtils;
|
||||
import com.blankj.utilcode.util.ScreenUtils;
|
||||
import com.blankj.utilcode.util.Utils;
|
||||
import org.yameida.floatwindow.view.HiderView;
|
||||
|
||||
|
||||
public abstract class BaseFloatWindow extends Service {
|
||||
protected final String TAG = this.getClass().getSimpleName();
|
||||
|
||||
/**
|
||||
* 悬浮球 坐落 左 右 标记
|
||||
*/
|
||||
public static final int LEFT = 0;
|
||||
public static final int RIGHT = 1;
|
||||
|
||||
/**
|
||||
* 记录 logo 停放的位置,以备下次恢复
|
||||
*/
|
||||
protected final String LOCATION_X = TAG + "_x";
|
||||
protected final String LOCATION_Y = TAG + "_y";
|
||||
|
||||
/**
|
||||
* 停靠默认位置
|
||||
*/
|
||||
protected int mDefaultLocation = RIGHT;
|
||||
|
||||
|
||||
/**
|
||||
* 悬浮窗 坐落 位置
|
||||
*/
|
||||
protected int mHintLocation = mDefaultLocation;
|
||||
|
||||
|
||||
/**
|
||||
* 记录当前手指位置在屏幕上的横坐标值
|
||||
*/
|
||||
private float mXInScreen;
|
||||
|
||||
/**
|
||||
* 记录当前手指位置在屏幕上的纵坐标值
|
||||
*/
|
||||
private float mYInScreen;
|
||||
|
||||
/**
|
||||
* 记录手指按下时在屏幕上的横坐标的值
|
||||
*/
|
||||
private float mXDownInScreen;
|
||||
|
||||
/**
|
||||
* 记录手指按下时在屏幕上的纵坐标的值
|
||||
*/
|
||||
private float mYDownInScreen;
|
||||
|
||||
/**
|
||||
* 记录手指按下时在小悬浮窗的View上的横坐标的值
|
||||
*/
|
||||
private float mXInView;
|
||||
|
||||
/**
|
||||
* 记录手指按下时在小悬浮窗的View上的纵坐标的值
|
||||
*/
|
||||
private float mYinview;
|
||||
|
||||
/**
|
||||
* 记录屏幕的宽度
|
||||
*/
|
||||
private int mScreenWidth;
|
||||
|
||||
protected WindowManager mWindowManager;
|
||||
protected WindowManager.LayoutParams params;
|
||||
|
||||
private Context context = Utils.getApp();
|
||||
|
||||
/**
|
||||
* 退出悬浮窗区域
|
||||
*/
|
||||
private HiderView mHiderView = new HiderView(context);
|
||||
private boolean showHider = true;
|
||||
|
||||
|
||||
/**
|
||||
* 用于 定时 隐藏 logo的定时器
|
||||
*/
|
||||
private CountDownTimer mHideTimer;
|
||||
|
||||
|
||||
/**
|
||||
* float menu的高度
|
||||
*/
|
||||
private Handler mHandler = new Handler(Looper.getMainLooper());
|
||||
|
||||
|
||||
/**
|
||||
* 悬浮窗左右移动到默认位置 动画的 加速器
|
||||
*/
|
||||
private Interpolator mLinearInterpolator = new LinearInterpolator();
|
||||
|
||||
/**
|
||||
* 标记是否拖动中
|
||||
*/
|
||||
private boolean isDrag = false;
|
||||
|
||||
/**
|
||||
* 用于恢复悬浮球的location的属性动画值
|
||||
*/
|
||||
private int mResetLocationValue;
|
||||
|
||||
/**
|
||||
* 限制拖动的y轴坐标
|
||||
*/
|
||||
protected int minY = 0;
|
||||
protected int maxY = ScreenUtils.getScreenHeight();
|
||||
|
||||
@Override
|
||||
public IBinder onBind(Intent intent) {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 这个事件用于处理移动、自定义点击或者其它事情,return true可以保证onclick事件失效
|
||||
*/
|
||||
private View.OnTouchListener touchListener = new View.OnTouchListener() {
|
||||
@Override
|
||||
public boolean onTouch(View v, MotionEvent event) {
|
||||
switch (event.getAction()) {
|
||||
case MotionEvent.ACTION_DOWN:
|
||||
floatEventDown(event);
|
||||
break;
|
||||
case MotionEvent.ACTION_MOVE:
|
||||
floatEventMove(event);
|
||||
break;
|
||||
case MotionEvent.ACTION_UP:
|
||||
case MotionEvent.ACTION_CANCEL:
|
||||
floatEventUp();
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
ValueAnimator valueAnimator = null;
|
||||
protected boolean isExtended = false;
|
||||
|
||||
protected View logoView;
|
||||
protected View rightView;
|
||||
protected View leftView;
|
||||
|
||||
private GetViewCallback mGetViewCallback;
|
||||
|
||||
protected BaseFloatWindow() {
|
||||
initFloatWindow();
|
||||
initTimer();
|
||||
initFloatView();
|
||||
|
||||
}
|
||||
|
||||
private void initFloatView() {
|
||||
LayoutInflater inflater = LayoutInflater.from(context);
|
||||
logoView = mGetViewCallback == null ? getLogoView(inflater) : mGetViewCallback.getLogoView(inflater);
|
||||
leftView = mGetViewCallback == null ? getLeftView(inflater) : mGetViewCallback.getLeftView(inflater);
|
||||
rightView = mGetViewCallback == null ? getRightView(inflater) : mGetViewCallback.getRightView(inflater);
|
||||
|
||||
if (logoView == null) {
|
||||
throw new IllegalArgumentException("Must impl GetViewCallback or impl " + this.getClass().getSimpleName() + "and make getLogoView() not return null !");
|
||||
}
|
||||
|
||||
logoView.setOnTouchListener(touchListener);//恢复touch事件
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化 隐藏悬浮球的定时器
|
||||
*/
|
||||
private void initTimer() {
|
||||
mHideTimer = new CountDownTimer(2000, 10) { //悬浮窗超过5秒没有操作的话会自动隐藏
|
||||
@Override
|
||||
public void onTick(long millisUntilFinished) {
|
||||
if (isExtended) {
|
||||
mHideTimer.cancel();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFinish() {
|
||||
if (isExtended) {
|
||||
mHideTimer.cancel();
|
||||
return;
|
||||
}
|
||||
if (!isDrag) {
|
||||
if (mHintLocation == LEFT) {
|
||||
if (mGetViewCallback == null) {
|
||||
shrinkLeftLogoView(logoView);
|
||||
} else {
|
||||
mGetViewCallback.shrinkLeftLogoView(logoView);
|
||||
}
|
||||
} else {
|
||||
if (mGetViewCallback == null) {
|
||||
shrinkRightLogoView(logoView);
|
||||
} else {
|
||||
mGetViewCallback.shrinkRightLogoView(logoView);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化悬浮球 window
|
||||
*/
|
||||
private void initFloatWindow() {
|
||||
params = new WindowManager.LayoutParams();
|
||||
mWindowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
|
||||
|
||||
if (Build.VERSION.SDK_INT >= 23) {
|
||||
if (!Settings.canDrawOverlays(context)) {
|
||||
if (Build.VERSION.SDK_INT >= 26) {
|
||||
params.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
|
||||
} else {
|
||||
params.type = WindowManager.LayoutParams.TYPE_SYSTEM_ALERT;
|
||||
}
|
||||
} else {
|
||||
if (Build.VERSION.SDK_INT >= 26) {
|
||||
params.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
|
||||
} else {
|
||||
params.type = WindowManager.LayoutParams.TYPE_SYSTEM_ALERT;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
params.type = WindowManager.LayoutParams.TYPE_SYSTEM_ALERT;
|
||||
}
|
||||
|
||||
mScreenWidth = mWindowManager.getDefaultDisplay().getWidth();
|
||||
int screenHeigth = mWindowManager.getDefaultDisplay().getHeight();
|
||||
params.format = PixelFormat.RGBA_8888;
|
||||
params.gravity = Gravity.LEFT | Gravity.TOP;
|
||||
params.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
|
||||
mHintLocation = getSetting(LOCATION_X, mDefaultLocation);
|
||||
int defaultY = ((screenHeigth) / 2) / 3;
|
||||
int y = getSetting(LOCATION_Y, defaultY);
|
||||
if (mHintLocation == LEFT) {
|
||||
params.x = 0;
|
||||
} else {
|
||||
params.x = mScreenWidth;
|
||||
}
|
||||
if (y != 0 && y != defaultY) {
|
||||
params.y = y;
|
||||
} else {
|
||||
params.y = defaultY;
|
||||
}
|
||||
params.alpha = 1;
|
||||
params.width = WindowManager.LayoutParams.WRAP_CONTENT;
|
||||
params.height = WindowManager.LayoutParams.WRAP_CONTENT;
|
||||
}
|
||||
|
||||
/**
|
||||
* 悬浮窗touch事件的 down 事件
|
||||
*/
|
||||
private void floatEventDown(MotionEvent event) {
|
||||
isDrag = false;
|
||||
mHideTimer.cancel();
|
||||
|
||||
if (mGetViewCallback == null) {
|
||||
resetLogoViewSize(mHintLocation, logoView);
|
||||
} else {
|
||||
mGetViewCallback.resetLogoViewSize(mHintLocation, logoView);
|
||||
}
|
||||
|
||||
mXInView = event.getX();
|
||||
mYinview = event.getY();
|
||||
mXDownInScreen = event.getRawX();
|
||||
mYDownInScreen = event.getRawY();
|
||||
mXInScreen = event.getRawX();
|
||||
mYInScreen = event.getRawY();
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 悬浮窗touch事件的 move 事件
|
||||
*/
|
||||
private void floatEventMove(MotionEvent event) {
|
||||
mXInScreen = event.getRawX();
|
||||
mYInScreen = event.getRawY();
|
||||
|
||||
//连续移动的距离超过3则更新一次视图位置
|
||||
if (Math.abs(mXInScreen - mXDownInScreen) > logoView.getWidth() / 4 || Math.abs(mYInScreen - mYDownInScreen) > logoView.getWidth() / 4) {
|
||||
params.x = (int) (mXInScreen - mXInView);
|
||||
params.y = (int) (mYInScreen - mYinview) - logoView.getHeight() / 2;
|
||||
updateViewPosition(); // 手指移动的时候更新小悬浮窗的位置
|
||||
// double a = mScreenWidth / 2;
|
||||
// float offset = (float) ((a - (Math.abs(params.x - a))) / a);
|
||||
// if (mGetViewCallback == null) {
|
||||
// dragLogoViewOffset(logoView, isDrag, false, offset);
|
||||
// } else {
|
||||
// mGetViewCallback.dragLogoViewOffset(logoView, isDrag, false, offset);
|
||||
// }
|
||||
mHiderView.attachToWindow();
|
||||
} else {
|
||||
// isDrag = false;
|
||||
//// logoView.setDrag(false, 0, true);
|
||||
// if (mGetViewCallback == null) {
|
||||
// dragLogoViewOffset(logoView, false, true, 0);
|
||||
// } else {
|
||||
// mGetViewCallback.dragLogoViewOffset(logoView, false, true, 0);
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 悬浮窗touch事件的 up 事件
|
||||
*/
|
||||
private void floatEventUp() {
|
||||
if (mXInScreen < mScreenWidth / 2) { //在左边
|
||||
mHintLocation = LEFT;
|
||||
} else { //在右边
|
||||
mHintLocation = RIGHT;
|
||||
}
|
||||
|
||||
|
||||
valueAnimator = ValueAnimator.ofInt(64);
|
||||
valueAnimator.setInterpolator(mLinearInterpolator);
|
||||
valueAnimator.setDuration(1000);
|
||||
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
|
||||
@Override
|
||||
public void onAnimationUpdate(ValueAnimator animation) {
|
||||
mResetLocationValue = (int) animation.getAnimatedValue();
|
||||
mHandler.post(updatePositionRunnable);
|
||||
}
|
||||
});
|
||||
|
||||
valueAnimator.addListener(new Animator.AnimatorListener() {
|
||||
@Override
|
||||
public void onAnimationStart(Animator animation) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAnimationEnd(Animator animation) {
|
||||
if (Math.abs(params.x) < 0) {
|
||||
params.x = 0;
|
||||
} else if (Math.abs(params.x) > mScreenWidth) {
|
||||
params.x = mScreenWidth;
|
||||
}
|
||||
updateViewPosition();
|
||||
isDrag = false;
|
||||
if (mGetViewCallback == null) {
|
||||
dragLogoViewOffset(logoView, false, true, 0);
|
||||
} else {
|
||||
mGetViewCallback.dragLogoViewOffset(logoView, false, true, 0);
|
||||
}
|
||||
mHideTimer.start();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAnimationCancel(Animator animation) {
|
||||
if (Math.abs(params.x) < 0) {
|
||||
params.x = 0;
|
||||
} else if (Math.abs(params.x) > mScreenWidth) {
|
||||
params.x = mScreenWidth;
|
||||
}
|
||||
|
||||
updateViewPosition();
|
||||
isDrag = false;
|
||||
if (mGetViewCallback == null) {
|
||||
dragLogoViewOffset(logoView, false, true, 0);
|
||||
} else {
|
||||
mGetViewCallback.dragLogoViewOffset(logoView, false, true, 0);
|
||||
}
|
||||
mHideTimer.start();
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAnimationRepeat(Animator animation) {
|
||||
|
||||
}
|
||||
});
|
||||
if (!valueAnimator.isRunning()) {
|
||||
valueAnimator.start();
|
||||
}
|
||||
|
||||
//这里需要判断如果如果手指所在位置和logo所在位置在一个宽度内则不移动,
|
||||
if (Math.abs(mXInScreen - mXDownInScreen) > logoView.getWidth() / 5F || Math.abs(mYInScreen - mYDownInScreen) > logoView.getHeight() / 5F) {
|
||||
isDrag = false;
|
||||
} else {
|
||||
openMenu();
|
||||
}
|
||||
|
||||
mHiderView.release();
|
||||
if (mHiderView.mLp != null) {
|
||||
int lx = mScreenWidth / 2 - mHiderView.getWidth() / 2;
|
||||
int ly = mHiderView.mLp.y + BarUtils.getStatusBarHeight();
|
||||
int rx = lx + mHiderView.getWidth() + logoView.getWidth();
|
||||
int ry = ly + mHiderView.getHeight() + logoView.getHeight();
|
||||
if (mXInScreen >= lx && mXInScreen <= rx
|
||||
&& mYInScreen >= ly && mYInScreen <= ry) {
|
||||
valueAnimator.cancel();
|
||||
// 复原X
|
||||
if (mXDownInScreen < mScreenWidth / 2) { //在左边
|
||||
mHintLocation = LEFT;
|
||||
params.x = 0;
|
||||
} else { //在右边
|
||||
mHintLocation = RIGHT;
|
||||
params.x = mScreenWidth;
|
||||
}
|
||||
// 复原Y
|
||||
params.y = (int) mYDownInScreen;
|
||||
// 滑动的位置在隐藏视图内
|
||||
hide();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 手指离开屏幕后 用于恢复 悬浮球的 logo 的左右位置
|
||||
*/
|
||||
private Runnable updatePositionRunnable = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
isDrag = true;
|
||||
checkPosition();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 用于检查并更新悬浮球的位置
|
||||
*/
|
||||
private void checkPosition() {
|
||||
if (params.x > 0 && params.x < mScreenWidth) {
|
||||
if (mHintLocation == LEFT) {
|
||||
params.x = params.x - mResetLocationValue;
|
||||
} else {
|
||||
params.x = params.x + mResetLocationValue;
|
||||
}
|
||||
updateViewPosition();
|
||||
double a = mScreenWidth / 2;
|
||||
float offset = (float) ((a - (Math.abs(params.x - a))) / a);
|
||||
// logoView.setDrag(isDrag, offset, true);
|
||||
if (mGetViewCallback == null) {
|
||||
dragLogoViewOffset(logoView, false, true, 0);
|
||||
} else {
|
||||
mGetViewCallback.dragLogoViewOffset(logoView, isDrag, true, offset);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (Math.abs(params.x) < 0) {
|
||||
params.x = 0;
|
||||
} else if (Math.abs(params.x) > mScreenWidth) {
|
||||
params.x = mScreenWidth;
|
||||
}
|
||||
if (valueAnimator.isRunning()) {
|
||||
valueAnimator.cancel();
|
||||
}
|
||||
|
||||
updateViewPosition();
|
||||
isDrag = false;
|
||||
}
|
||||
|
||||
public void show() {
|
||||
try {
|
||||
dismiss();
|
||||
if (mWindowManager != null && params != null && logoView != null) {
|
||||
params.width = WindowManager.LayoutParams.WRAP_CONTENT;
|
||||
params.height = WindowManager.LayoutParams.WRAP_CONTENT;
|
||||
mWindowManager.addView(logoView, params);
|
||||
}
|
||||
if (mHideTimer != null) {
|
||||
mHideTimer.start();
|
||||
} else {
|
||||
initTimer();
|
||||
mHideTimer.start();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public void hide() {
|
||||
dismiss();
|
||||
}
|
||||
|
||||
/**
|
||||
* 打开菜单/关闭菜单
|
||||
*/
|
||||
protected void openMenu() {
|
||||
if (isDrag) return;
|
||||
|
||||
if (!isExtended) {
|
||||
// logoView.setDrawDarkBg(false);
|
||||
try {
|
||||
mWindowManager.removeViewImmediate(logoView);
|
||||
params.width = WindowManager.LayoutParams.MATCH_PARENT;
|
||||
params.height = WindowManager.LayoutParams.MATCH_PARENT;
|
||||
if (mHintLocation == RIGHT) {
|
||||
mWindowManager.addView(rightView, params);
|
||||
if (mGetViewCallback == null) {
|
||||
rightViewOpened(rightView);
|
||||
} else {
|
||||
mGetViewCallback.rightViewOpened(rightView);
|
||||
}
|
||||
} else {
|
||||
mWindowManager.addView(leftView, params);
|
||||
if (mGetViewCallback == null) {
|
||||
leftViewOpened(leftView);
|
||||
} else {
|
||||
mGetViewCallback.leftViewOpened(leftView);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
isExtended = true;
|
||||
mHideTimer.cancel();
|
||||
} else {
|
||||
// logoView.setDrawDarkBg(true);
|
||||
try {
|
||||
mWindowManager.removeViewImmediate(mHintLocation == LEFT ? leftView : rightView);
|
||||
params.width = WindowManager.LayoutParams.WRAP_CONTENT;
|
||||
params.height = WindowManager.LayoutParams.WRAP_CONTENT;
|
||||
mWindowManager.addView(logoView, params);
|
||||
if (mGetViewCallback == null) {
|
||||
leftOrRightViewClosed(logoView);
|
||||
} else {
|
||||
mGetViewCallback.leftOrRightViewClosed(logoView);
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
isExtended = false;
|
||||
mHideTimer.start();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 更新悬浮窗在屏幕中的位置。
|
||||
*/
|
||||
private void updateViewPosition() {
|
||||
isDrag = true;
|
||||
try {
|
||||
if (!isExtended) {
|
||||
if (minY == 0) minY = logoView.getHeight();
|
||||
if (maxY == ScreenUtils.getScreenHeight()) maxY -= logoView.getHeight();
|
||||
if (params.y < minY) params.y = minY;
|
||||
if (params.y > maxY) params.y = maxY;
|
||||
mWindowManager.updateViewLayout(logoView, params);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 移除所有悬浮窗 释放资源
|
||||
*/
|
||||
public void dismiss() {
|
||||
//记录上次的位置logo的停放位置,以备下次恢复
|
||||
saveSetting(LOCATION_X, mHintLocation);
|
||||
saveSetting(LOCATION_Y, params.y);
|
||||
logoView.clearAnimation();
|
||||
try {
|
||||
mHideTimer.cancel();
|
||||
if (isExtended) {
|
||||
mWindowManager.removeViewImmediate(mHintLocation == LEFT ? leftView : rightView);
|
||||
} else {
|
||||
if (logoView.getParent() != null) {
|
||||
mWindowManager.removeViewImmediate(logoView);
|
||||
}
|
||||
}
|
||||
isExtended = false;
|
||||
isDrag = false;
|
||||
if (mGetViewCallback == null) {
|
||||
onDestroyed();
|
||||
} else {
|
||||
mGetViewCallback.onDestroyed();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract View getLeftView(LayoutInflater inflater);
|
||||
|
||||
protected abstract View getRightView(LayoutInflater inflater);
|
||||
|
||||
protected abstract View getLogoView(LayoutInflater inflater);
|
||||
|
||||
protected abstract void resetLogoViewSize(int hintLocation, View logoView);//logo恢复原始大小
|
||||
|
||||
protected abstract void dragLogoViewOffset(View logoView, boolean isDrag, boolean isResetPosition, float offset);
|
||||
|
||||
protected abstract void shrinkLeftLogoView(View logoView);//logo左边收缩
|
||||
|
||||
protected abstract void shrinkRightLogoView(View logoView);//logo右边收缩
|
||||
|
||||
protected abstract void leftViewOpened(View leftView);//左菜单打开
|
||||
|
||||
protected abstract void rightViewOpened(View rightView);//右菜单打开
|
||||
|
||||
protected abstract void leftOrRightViewClosed(View logoView);
|
||||
|
||||
protected abstract void onDestroyed();
|
||||
|
||||
public interface GetViewCallback {
|
||||
View getLeftView(LayoutInflater inflater);
|
||||
|
||||
View getRightView(LayoutInflater inflater);
|
||||
|
||||
View getLogoView(LayoutInflater inflater);
|
||||
|
||||
|
||||
void resetLogoViewSize(int hintLocation, View logoView);//logo恢复原始大小
|
||||
|
||||
void dragLogoViewOffset(View logoView, boolean isDrag, boolean isResetPosition, float offset);//logo正被拖动,或真在恢复原位
|
||||
|
||||
void shrinkLeftLogoView(View logoView);//logo左边收缩
|
||||
|
||||
void shrinkRightLogoView(View logoView);//logo右边收缩
|
||||
|
||||
void leftViewOpened(View leftView);//左菜单打开
|
||||
|
||||
void rightViewOpened(View rightView);//右菜单打开
|
||||
|
||||
void leftOrRightViewClosed(View logoView);
|
||||
|
||||
void onDestroyed();
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 用于保存悬浮球的位置记录
|
||||
*
|
||||
* @param key String
|
||||
* @param defaultValue int
|
||||
* @return int
|
||||
*/
|
||||
private int getSetting(String key, int defaultValue) {
|
||||
try {
|
||||
SharedPreferences sharedata = context.getSharedPreferences("floatLogo", 0);
|
||||
return sharedata.getInt(key, defaultValue);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* 用于保存悬浮球的位置记录
|
||||
*
|
||||
* @param key String
|
||||
* @param value int
|
||||
*/
|
||||
public void saveSetting(String key, int value) {
|
||||
try {
|
||||
SharedPreferences.Editor sharedata = context.getSharedPreferences("floatLogo", 0).edit();
|
||||
sharedata.putInt(key, value);
|
||||
sharedata.apply();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onConfigurationChanged(Configuration newConfig) {
|
||||
super.onConfigurationChanged(newConfig);
|
||||
if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT) {
|
||||
} else {
|
||||
}
|
||||
mScreenWidth = mWindowManager.getDefaultDisplay().getWidth();
|
||||
if (mHintLocation == RIGHT) {
|
||||
params.x = mScreenWidth;
|
||||
}
|
||||
show();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,192 @@
|
||||
package org.yameida.floatwindow
|
||||
|
||||
import android.app.Notification
|
||||
import android.app.NotificationChannel
|
||||
import android.app.NotificationManager
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.os.Binder
|
||||
import android.os.Build
|
||||
import android.os.IBinder
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.widget.FrameLayout
|
||||
import com.blankj.utilcode.util.*
|
||||
|
||||
import org.yameida.floatwindow.listener.FloatWindowListener
|
||||
import kotlinx.android.synthetic.main.layout_menu_left.view.*
|
||||
import kotlinx.android.synthetic.main.layout_menu_logo.view.*
|
||||
import kotlinx.android.synthetic.main.layout_menu_right.view.*
|
||||
import org.yameida.floatwindow.listener.OnClickListener
|
||||
|
||||
/**
|
||||
* Created by Gallon on 2019/9/7.
|
||||
*/
|
||||
|
||||
class DefaultFloatService : BaseFloatWindow(), View.OnClickListener {
|
||||
|
||||
// private var currentStatus = RecordStatusManager.PLAY_STATUS_STOP
|
||||
private var active = false
|
||||
private var context = Utils.getApp()
|
||||
private var manager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
|
||||
private val CHANNEL_ID_STRING = "907"
|
||||
var floatWindowListener: FloatWindowListener? = null
|
||||
var onClickListener: OnClickListener? = null
|
||||
|
||||
inner class DefaultFloatServiceBinder : Binder() {
|
||||
fun getService() = this@DefaultFloatService
|
||||
}
|
||||
|
||||
init {
|
||||
minY = SizeUtils.dp2px(100F)
|
||||
maxY = ScreenUtils.getScreenHeight() - SizeUtils.dp2px(150F)
|
||||
}
|
||||
|
||||
override fun onBind(intent: Intent?): IBinder? = DefaultFloatServiceBinder()
|
||||
|
||||
override fun onCreate() {
|
||||
super.onCreate()
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
val mChannel = NotificationChannel(CHANNEL_ID_STRING, "float", NotificationManager.IMPORTANCE_HIGH)
|
||||
manager.createNotificationChannel(mChannel)
|
||||
val notification = Notification.Builder(context, CHANNEL_ID_STRING).build()
|
||||
startForeground(1, notification)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
|
||||
LogUtils.d(TAG, "onStartCommand: ${intent?.data}")
|
||||
show()
|
||||
return super.onStartCommand(intent, flags, startId)
|
||||
}
|
||||
|
||||
override fun show() {
|
||||
super.show()
|
||||
// FloatWindowManager.isShow = true
|
||||
floatWindowListener?.show()
|
||||
}
|
||||
|
||||
override fun hide() {
|
||||
super.hide()
|
||||
// FloatWindowManager.isShow = false
|
||||
floatWindowListener?.hide()
|
||||
}
|
||||
|
||||
override fun onClick(v: View) {
|
||||
LogUtils.v(TAG, "float onClick: ")
|
||||
openMenu()
|
||||
if (v == leftView.fl_window_background_left || v == rightView.fl_window_background_right) {
|
||||
onClickListener?.onClick(v,-1)
|
||||
}
|
||||
if (v == leftView.iv_logo_left || v == rightView.iv_logo_right || v == leftView.iv_logo_left2 || v == rightView.iv_logo_right2) {
|
||||
onClickListener?.onClick(v, 0)
|
||||
}
|
||||
if (v == leftView.iv_start_left || v == rightView.iv_start_right) {
|
||||
onClickListener?.onClick(v,1)
|
||||
}
|
||||
if (v == leftView.iv_shot_left || v == rightView.iv_shot_right) {
|
||||
onClickListener?.onClick(v,2)
|
||||
}
|
||||
if (v == leftView.iv_back_left || v == rightView.iv_back_right) {
|
||||
onClickListener?.onClick(v,3)
|
||||
}
|
||||
if (v == leftView.iv_settings_left || v == rightView.iv_settings_right) {
|
||||
onClickListener?.onClick(v,4)
|
||||
}
|
||||
if (v == leftView.iv_resume_pause_left || v == rightView.iv_resume_pause_right) {
|
||||
onClickListener?.onClick(v,5)
|
||||
}
|
||||
if (v == leftView.iv_stop_left || v == rightView.iv_stop_right) {
|
||||
onClickListener?.onClick(v,6)
|
||||
}
|
||||
}
|
||||
|
||||
override fun getLeftView(inflater: LayoutInflater): View {
|
||||
leftView = inflater.inflate(R.layout.layout_menu_left, null)
|
||||
leftView.iv_logo_left.setOnClickListener(this)
|
||||
leftView.iv_logo_left2.setOnClickListener(this)
|
||||
leftView.iv_start_left.setOnClickListener(this)
|
||||
leftView.iv_shot_left.setOnClickListener(this)
|
||||
leftView.iv_back_left.setOnClickListener(this)
|
||||
leftView.iv_resume_pause_left.setOnClickListener(this)
|
||||
leftView.iv_stop_left.setOnClickListener(this)
|
||||
leftView.iv_settings_left.setOnClickListener(this)
|
||||
leftView.fl_window_background_left.setOnClickListener(this)
|
||||
return leftView
|
||||
}
|
||||
|
||||
override fun getRightView(inflater: LayoutInflater): View {
|
||||
rightView = inflater.inflate(R.layout.layout_menu_right, null)
|
||||
rightView.iv_logo_right.setOnClickListener(this)
|
||||
rightView.iv_logo_right2.setOnClickListener(this)
|
||||
rightView.iv_start_right.setOnClickListener(this)
|
||||
rightView.iv_shot_right.setOnClickListener(this)
|
||||
rightView.iv_back_right.setOnClickListener(this)
|
||||
rightView.iv_resume_pause_right.setOnClickListener(this)
|
||||
rightView.iv_stop_right.setOnClickListener(this)
|
||||
rightView.iv_settings_right.setOnClickListener(this)
|
||||
rightView.fl_window_background_right.setOnClickListener(this)
|
||||
return rightView
|
||||
}
|
||||
|
||||
override fun getLogoView(inflater: LayoutInflater): View {
|
||||
return inflater.inflate(R.layout.layout_menu_logo, null)
|
||||
}
|
||||
|
||||
override fun resetLogoViewSize(hintLocation: Int, logoView: View) {
|
||||
logoView.clearAnimation()
|
||||
logoView.translationX = 0f
|
||||
logoView.scaleX = 1f
|
||||
logoView.scaleY = 1f
|
||||
logoView.alpha = 1f
|
||||
logoView.tv_float_time.textSize = 10f
|
||||
}
|
||||
|
||||
override fun dragLogoViewOffset(logoView: View, isDrag: Boolean, isResetPosition: Boolean, offset: Float) {
|
||||
if (isDrag && offset > 0) {
|
||||
logoView.scaleX = 1 + offset
|
||||
logoView.scaleY = 1 + offset
|
||||
} else {
|
||||
logoView.translationX = 0f
|
||||
logoView.scaleX = 1f
|
||||
logoView.scaleY = 1f
|
||||
}
|
||||
|
||||
logoView.rotation = offset * 360
|
||||
}
|
||||
|
||||
public override fun shrinkLeftLogoView(smallView: View) {
|
||||
smallView.translationX = (-smallView.width / 4).toFloat()
|
||||
smallView.alpha = 0.35f
|
||||
logoView.tv_float_time.textSize = 7f
|
||||
}
|
||||
|
||||
public override fun shrinkRightLogoView(smallView: View) {
|
||||
smallView.translationX = (smallView.width / 4).toFloat()
|
||||
smallView.alpha = 0.35f
|
||||
logoView.tv_float_time.textSize = 7f
|
||||
}
|
||||
|
||||
public override fun leftViewOpened(leftView: View) {
|
||||
val layoutParams = leftView.fl_window_measure_left.layoutParams as FrameLayout.LayoutParams
|
||||
leftView.fl_window_measure_left.measure(0, 0)
|
||||
layoutParams.topMargin = (params.y - leftView.fl_window_measure_left.measuredHeight / 2 - leftView.iv_logo_left.measuredHeight / 2)
|
||||
leftView.fl_window_measure_left.layoutParams = layoutParams
|
||||
// ToastUtils.showShort("左边的菜单被打开了")
|
||||
}
|
||||
|
||||
public override fun rightViewOpened(rightView: View) {
|
||||
val layoutParams = rightView.fl_window_measure_right.layoutParams as FrameLayout.LayoutParams
|
||||
rightView.fl_window_measure_right.measure(0, 0)
|
||||
layoutParams.topMargin = params.y - rightView.fl_window_measure_right.measuredHeight / 2 - rightView.iv_logo_right.measuredHeight / 2
|
||||
layoutParams.leftMargin = ScreenUtils.getScreenWidth() - rightView.fl_window_measure_right.measuredWidth
|
||||
rightView.fl_window_measure_right.layoutParams = layoutParams
|
||||
// ToastUtils.showShort("右边的菜单被打开了")
|
||||
}
|
||||
|
||||
public override fun leftOrRightViewClosed(smallView: View) {
|
||||
// Toast.makeText(context, "菜单被关闭了", Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
|
||||
override fun onDestroyed() {}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
package org.yameida.floatwindow
|
||||
|
||||
import android.content.Intent
|
||||
import android.os.Build
|
||||
import com.blankj.utilcode.util.Utils
|
||||
|
||||
/**
|
||||
* Created by Gallon on 2019/9/5.
|
||||
*/
|
||||
object FloatWindowManager {
|
||||
private val TAG = FloatWindowManager::class.java.simpleName
|
||||
|
||||
private var context = Utils.getApp()
|
||||
|
||||
fun show(service: Class<out BaseFloatWindow>, intent: Intent? = null) {
|
||||
startServiceSafe(Intent(context, service).apply {
|
||||
if (intent != null) {
|
||||
this.putExtras(intent)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fun hide(service: Class<out BaseFloatWindow>, intent: Intent? = null) {
|
||||
startServiceSafe(Intent(context, service).apply {
|
||||
if (intent != null) {
|
||||
this.putExtras(intent)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
private fun startServiceSafe(intent: Intent) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
context.startForegroundService(intent)
|
||||
} else {
|
||||
context.startService(intent)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
package org.yameida.floatwindow.listener
|
||||
|
||||
/**
|
||||
* Created by Gallon on 2019/8/11.
|
||||
*/
|
||||
interface FloatWindowListener {
|
||||
fun show()
|
||||
|
||||
fun hide()
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package org.yameida.floatwindow.listener
|
||||
|
||||
import android.view.View
|
||||
|
||||
/**
|
||||
* Created by Gallon on 2019/8/11.
|
||||
*/
|
||||
interface OnClickListener {
|
||||
|
||||
fun onClick(v: View, event: Int)
|
||||
}
|
||||
@@ -0,0 +1,118 @@
|
||||
package org.yameida.floatwindow.view;
|
||||
|
||||
import android.animation.Animator;
|
||||
import android.animation.ValueAnimator;
|
||||
import android.content.Context;
|
||||
import android.graphics.PixelFormat;
|
||||
import android.os.Build;
|
||||
import android.provider.Settings;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.Gravity;
|
||||
import android.view.WindowManager;
|
||||
import android.widget.LinearLayout;
|
||||
|
||||
import org.yameida.floatwindow.R;
|
||||
|
||||
|
||||
public class HiderView extends LinearLayout {
|
||||
private Context mContext;
|
||||
private WindowManager mWindowManager;
|
||||
public WindowManager.LayoutParams mLp;
|
||||
private ValueAnimator valueAnimator;
|
||||
private int mResetLocationValue;
|
||||
|
||||
public HiderView(Context context) {
|
||||
super(context);
|
||||
this.mContext = context;
|
||||
init();
|
||||
}
|
||||
|
||||
public HiderView(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
this.mContext = context;
|
||||
init();
|
||||
}
|
||||
|
||||
private void init() {
|
||||
inflate(mContext, R.layout.widget_hiderview_ll, this);
|
||||
}
|
||||
|
||||
public void attachToWindow() {
|
||||
if (this.getParent() != null) {
|
||||
return;
|
||||
}
|
||||
mWindowManager = (WindowManager) mContext
|
||||
.getSystemService(Context.WINDOW_SERVICE);
|
||||
mLp = new WindowManager.LayoutParams();
|
||||
if (Build.VERSION.SDK_INT >= 23) {
|
||||
if (!Settings.canDrawOverlays(getContext())) {
|
||||
if (Build.VERSION.SDK_INT >= 26) {
|
||||
mLp.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
|
||||
} else {
|
||||
mLp.type = WindowManager.LayoutParams.TYPE_SYSTEM_ALERT;
|
||||
}
|
||||
} else {
|
||||
if (Build.VERSION.SDK_INT >= 26) {
|
||||
mLp.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
|
||||
} else {
|
||||
mLp.type = WindowManager.LayoutParams.TYPE_SYSTEM_ALERT;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
mLp.type = WindowManager.LayoutParams.TYPE_SYSTEM_ALERT;
|
||||
}
|
||||
// mLp.type = WindowManager.LayoutParams.TYPE_SYSTEM_ALERT;
|
||||
mLp.format = PixelFormat.RGBA_8888;
|
||||
mLp.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
|
||||
| WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
|
||||
mLp.gravity = Gravity.CENTER | Gravity.TOP;
|
||||
mLp.width = WindowManager.LayoutParams.WRAP_CONTENT;
|
||||
mLp.height = WindowManager.LayoutParams.WRAP_CONTENT;
|
||||
int y = mWindowManager.getDefaultDisplay().getHeight();
|
||||
mLp.y = y;
|
||||
mWindowManager.addView(this, mLp);
|
||||
|
||||
valueAnimator = ValueAnimator.ofInt(0, y / 4);
|
||||
valueAnimator.setDuration(200);
|
||||
|
||||
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
|
||||
@Override
|
||||
public void onAnimationUpdate(ValueAnimator animation) {
|
||||
mResetLocationValue = (int) animation.getAnimatedValue();
|
||||
mLp.y = y - getHeight() - mResetLocationValue;
|
||||
mWindowManager.updateViewLayout(HiderView.this, mLp);
|
||||
}
|
||||
});
|
||||
|
||||
valueAnimator.addListener(new Animator.AnimatorListener() {
|
||||
@Override
|
||||
public void onAnimationStart(Animator animation) {}
|
||||
|
||||
@Override
|
||||
public void onAnimationEnd(Animator animation) {
|
||||
mWindowManager.updateViewLayout(HiderView.this, mLp);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAnimationCancel(Animator animation) {
|
||||
mWindowManager.updateViewLayout(HiderView.this, mLp);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAnimationRepeat(Animator animation) {}
|
||||
});
|
||||
if (!valueAnimator.isRunning()) {
|
||||
valueAnimator.start();
|
||||
}
|
||||
}
|
||||
|
||||
public void release() {
|
||||
if (this.getParent() != null) {
|
||||
if (valueAnimator.isRunning()) {
|
||||
valueAnimator.cancel();
|
||||
}
|
||||
mWindowManager.removeView(this);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
After Width: | Height: | Size: 306 B |
BIN
floatwindow/src/main/res/drawable-xxhdpi/back_icon.png
Normal file
|
After Width: | Height: | Size: 1.8 KiB |
BIN
floatwindow/src/main/res/drawable-xxhdpi/bg_float_guide.png
Normal file
|
After Width: | Height: | Size: 2.6 KiB |
BIN
floatwindow/src/main/res/drawable-xxhdpi/float_icon_home.png
Normal file
|
After Width: | Height: | Size: 3.2 KiB |
BIN
floatwindow/src/main/res/drawable-xxhdpi/float_icon_pause.png
Normal file
|
After Width: | Height: | Size: 3.0 KiB |
BIN
floatwindow/src/main/res/drawable-xxhdpi/float_icon_play.png
Normal file
|
After Width: | Height: | Size: 3.6 KiB |
BIN
floatwindow/src/main/res/drawable-xxhdpi/float_icon_record.png
Normal file
|
After Width: | Height: | Size: 3.2 KiB |
BIN
floatwindow/src/main/res/drawable-xxhdpi/float_icon_setting.png
Normal file
|
After Width: | Height: | Size: 3.2 KiB |
BIN
floatwindow/src/main/res/drawable-xxhdpi/float_icon_stop.png
Normal file
|
After Width: | Height: | Size: 2.8 KiB |
BIN
floatwindow/src/main/res/drawable-xxhdpi/settings_directory.png
Normal file
|
After Width: | Height: | Size: 322 B |
BIN
floatwindow/src/main/res/drawable-xxhdpi/settings_fps.png
Normal file
|
After Width: | Height: | Size: 145 B |
BIN
floatwindow/src/main/res/drawable-xxhdpi/settings_hd.png
Normal file
|
After Width: | Height: | Size: 342 B |
BIN
floatwindow/src/main/res/drawable-xxhdpi/settings_hq.png
Normal file
|
After Width: | Height: | Size: 368 B |
BIN
floatwindow/src/main/res/drawable-xxhdpi/settings_language.png
Normal file
|
After Width: | Height: | Size: 697 B |
BIN
floatwindow/src/main/res/drawable-xxhdpi/settings_no_pop.png
Normal file
|
After Width: | Height: | Size: 734 B |
|
After Width: | Height: | Size: 616 B |
BIN
floatwindow/src/main/res/drawable-xxhdpi/settings_rate_us.png
Normal file
|
After Width: | Height: | Size: 1.9 KiB |
BIN
floatwindow/src/main/res/drawable-xxhdpi/settings_share.png
Normal file
|
After Width: | Height: | Size: 663 B |
BIN
floatwindow/src/main/res/drawable-xxhdpi/tab_settings_check.png
Normal file
|
After Width: | Height: | Size: 1.4 KiB |
BIN
floatwindow/src/main/res/drawable-xxhdpi/widget_float_hide.png
Normal file
|
After Width: | Height: | Size: 67 KiB |
BIN
floatwindow/src/main/res/drawable-xxhdpi/widget_guide_finger.png
Normal file
|
After Width: | Height: | Size: 2.9 KiB |
BIN
floatwindow/src/main/res/drawable-xxhdpi/widget_tip_button.png
Normal file
|
After Width: | Height: | Size: 14 KiB |
22
floatwindow/src/main/res/drawable/comment_gray_btn.xml
Normal file
@@ -0,0 +1,22 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:state_pressed="true">
|
||||
<shape>
|
||||
<solid android:color="#ddd" />
|
||||
<corners android:radius="5dp" />
|
||||
</shape>
|
||||
</item>
|
||||
<item android:state_enabled="false">
|
||||
<shape>
|
||||
<solid android:color="@android:color/transparent" />
|
||||
<corners android:radius="5dp" />
|
||||
<stroke android:width="1dp" android:color="@color/c8c8c8" />
|
||||
</shape>
|
||||
</item>
|
||||
<item>
|
||||
<shape>
|
||||
<solid android:color="#aaa" />
|
||||
<corners android:radius="5dp" />
|
||||
</shape>
|
||||
</item>
|
||||
</selector>
|
||||
22
floatwindow/src/main/res/drawable/comment_red_btn.xml
Normal file
@@ -0,0 +1,22 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:state_pressed="true">
|
||||
<shape>
|
||||
<solid android:color="@color/color_dashen_passed" />
|
||||
<corners android:radius="5dp" />
|
||||
</shape>
|
||||
</item>
|
||||
<item android:state_enabled="false">
|
||||
<shape>
|
||||
<solid android:color="@android:color/transparent" />
|
||||
<corners android:radius="5dp" />
|
||||
<stroke android:width="1dp" android:color="@color/c8c8c8" />
|
||||
</shape>
|
||||
</item>
|
||||
<item>
|
||||
<shape>
|
||||
<solid android:color="@color/color_dashen" />
|
||||
<corners android:radius="5dp" />
|
||||
</shape>
|
||||
</item>
|
||||
</selector>
|
||||
9
floatwindow/src/main/res/drawable/ic_arrow_back.xml
Normal file
@@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24.0"
|
||||
android:viewportHeight="24.0">
|
||||
<path
|
||||
android:fillColor="#FFFFFFFF"
|
||||
android:pathData="M20,11H7.83l5.59,-5.59L12,4l-8,8 8,8 1.41,-1.41L7.83,13H20v-2z"/>
|
||||
</vector>
|
||||
99
floatwindow/src/main/res/layout/layout_menu_left.xml
Normal file
@@ -0,0 +1,99 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/fl_window_background_left"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="#66333333">
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/fl_window_measure_left"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<RelativeLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="190dp"
|
||||
android:visibility="visible">
|
||||
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/iv_start_left"
|
||||
android:layout_width="@dimen/float_size"
|
||||
android:layout_height="@dimen/float_size"
|
||||
android:layout_marginEnd="@dimen/float_margin_start"
|
||||
android:src="@drawable/float_icon_record" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/iv_shot_left"
|
||||
android:layout_width="@dimen/float_size"
|
||||
android:layout_height="@dimen/float_size"
|
||||
android:layout_marginStart="@dimen/float_margin_start"
|
||||
android:layout_marginTop="29dp"
|
||||
android:src="@drawable/float_icon_pause" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/iv_back_left"
|
||||
android:layout_width="@dimen/float_size"
|
||||
android:layout_height="@dimen/float_size"
|
||||
android:layout_below="@id/iv_shot_left"
|
||||
android:layout_marginStart="@dimen/float_margin_start"
|
||||
android:layout_marginTop="2dp"
|
||||
android:src="@drawable/float_icon_home" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/iv_logo_left"
|
||||
android:layout_width="50dp"
|
||||
android:layout_height="50dp"
|
||||
android:layout_below="@id/iv_start_left"
|
||||
android:layout_marginStart="5dp"
|
||||
android:layout_marginTop="10dp"
|
||||
android:layout_marginEnd="55dp"
|
||||
android:src="@mipmap/ic_launcher_round" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/iv_settings_left"
|
||||
android:layout_width="@dimen/float_size"
|
||||
android:layout_height="@dimen/float_size"
|
||||
android:layout_below="@id/iv_logo_left"
|
||||
android:layout_marginTop="10dp"
|
||||
android:layout_marginEnd="@dimen/float_margin_start"
|
||||
android:scaleX="1.05"
|
||||
android:scaleY="1.05"
|
||||
android:src="@drawable/float_icon_setting" />
|
||||
|
||||
</RelativeLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="190dp"
|
||||
android:gravity="center_vertical"
|
||||
android:paddingStart="0dp"
|
||||
android:paddingEnd="2dp"
|
||||
android:visibility="gone">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/iv_logo_left2"
|
||||
android:layout_width="50dp"
|
||||
android:layout_height="50dp"
|
||||
android:layout_marginStart="2dp"
|
||||
android:src="@mipmap/ic_launcher_round" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/iv_resume_pause_left"
|
||||
android:layout_width="@dimen/float_size"
|
||||
android:layout_height="@dimen/float_size"
|
||||
android:layout_marginStart="2dp"
|
||||
android:src="@drawable/float_icon_pause" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/iv_stop_left"
|
||||
android:layout_width="@dimen/float_size"
|
||||
android:layout_height="@dimen/float_size"
|
||||
android:layout_marginStart="-5dp"
|
||||
android:src="@drawable/float_icon_stop" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</FrameLayout>
|
||||
|
||||
</FrameLayout>
|
||||
22
floatwindow/src/main/res/layout/layout_menu_logo.xml
Normal file
@@ -0,0 +1,22 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="@dimen/float_stand_size"
|
||||
android:gravity="center">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="@dimen/float_stand_size"
|
||||
android:layout_height="@dimen/float_stand_size"
|
||||
android:scaleType="centerInside"
|
||||
android:src="@mipmap/ic_launcher_round" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_float_time"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:textColor="@color/white"
|
||||
android:textSize="10sp"
|
||||
android:visibility="gone" />
|
||||
|
||||
</FrameLayout>
|
||||
94
floatwindow/src/main/res/layout/layout_menu_right.xml
Normal file
@@ -0,0 +1,94 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/fl_window_background_right"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="#66333333">
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/fl_window_measure_right"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<RelativeLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="190dp"
|
||||
android:visibility="visible">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/iv_start_right"
|
||||
android:layout_width="@dimen/float_size"
|
||||
android:layout_height="@dimen/float_size"
|
||||
android:layout_marginStart="@dimen/float_margin_start"
|
||||
android:src="@drawable/float_icon_record" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/iv_shot_right"
|
||||
android:layout_width="@dimen/float_size"
|
||||
android:layout_height="@dimen/float_size"
|
||||
android:layout_marginTop="29dp"
|
||||
android:src="@drawable/float_icon_pause" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/iv_back_right"
|
||||
android:layout_width="@dimen/float_size"
|
||||
android:layout_height="@dimen/float_size"
|
||||
android:layout_below="@id/iv_shot_right"
|
||||
android:layout_marginTop="2dp"
|
||||
android:src="@drawable/float_icon_home" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/iv_logo_right"
|
||||
android:layout_width="50dp"
|
||||
android:layout_height="50dp"
|
||||
android:layout_below="@id/iv_start_right"
|
||||
android:layout_marginStart="55dp"
|
||||
android:layout_marginTop="10dp"
|
||||
android:src="@mipmap/ic_launcher_round" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/iv_settings_right"
|
||||
android:layout_width="@dimen/float_size"
|
||||
android:layout_height="@dimen/float_size"
|
||||
android:layout_below="@id/iv_logo_right"
|
||||
android:layout_marginStart="@dimen/float_margin_start"
|
||||
android:layout_marginTop="10dp"
|
||||
android:scaleX="1.05"
|
||||
android:scaleY="1.05"
|
||||
android:src="@drawable/float_icon_setting" />
|
||||
|
||||
</RelativeLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="190dp"
|
||||
android:gravity="center_vertical"
|
||||
android:paddingEnd="2dp"
|
||||
android:paddingStart="0dp"
|
||||
android:visibility="gone">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/iv_stop_right"
|
||||
android:layout_width="@dimen/float_size"
|
||||
android:layout_height="@dimen/float_size"
|
||||
android:src="@drawable/float_icon_stop" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/iv_resume_pause_right"
|
||||
android:layout_width="@dimen/float_size"
|
||||
android:layout_height="@dimen/float_size"
|
||||
android:layout_marginStart="-5dp"
|
||||
android:src="@drawable/float_icon_pause" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/iv_logo_right2"
|
||||
android:layout_width="50dp"
|
||||
android:layout_height="50dp"
|
||||
android:layout_marginStart="2dp"
|
||||
android:src="@mipmap/ic_launcher_round" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</FrameLayout>
|
||||
|
||||
</FrameLayout>
|
||||
15
floatwindow/src/main/res/layout/widget_hiderview_ll.xml
Normal file
@@ -0,0 +1,15 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center"
|
||||
android:orientation="horizontal"
|
||||
>
|
||||
<!-- android:background="@color/balloonperformer_translucent"-->
|
||||
|
||||
<ImageView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:src="@drawable/widget_float_hide" />
|
||||
|
||||
</LinearLayout>
|
||||
BIN
floatwindow/src/main/res/mipmap-xxhdpi/ic_launcher.png
Normal file
|
After Width: | Height: | Size: 49 KiB |
BIN
floatwindow/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
Normal file
|
After Width: | Height: | Size: 45 KiB |
16
floatwindow/src/main/res/values/colors-rec.xml
Normal file
@@ -0,0 +1,16 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<color name="background">@color/color_f5f5f5</color>
|
||||
<color name="list_divider_line">@color/color_e5e5e5</color>
|
||||
<color name="white">#fff</color>
|
||||
<color name="color_333333">#333333</color>
|
||||
<color name="color_999999">#999999</color>
|
||||
<color name="color_b2000000">#b2000000</color>
|
||||
<color name="color_dashen">#ff5215</color>
|
||||
<color name="color_dashen_passed">#e54b12</color>
|
||||
<color name="float_time_color">#f58220</color>
|
||||
|
||||
<color name="color_e5e5e5">#e5e5e5</color>
|
||||
<color name="color_f5f5f5">#f5f5f5</color>
|
||||
<color name="c8c8c8">#c8c8c8</color>
|
||||
</resources>
|
||||
10
floatwindow/src/main/res/values/colors.xml
Normal file
@@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<color name="colorPrimary">#008577</color>
|
||||
<color name="colorPrimaryDark">#00574B</color>
|
||||
<color name="colorAccent">#D81B60</color>
|
||||
|
||||
<color name="bar_gray">#37474F</color>
|
||||
<color name="while_bg">#F7F7F7</color>
|
||||
|
||||
</resources>
|
||||
19
floatwindow/src/main/res/values/dimens.xml
Normal file
@@ -0,0 +1,19 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<dimen name="setting_start_padding">22dp</dimen>
|
||||
<dimen name="setting_end_start_padding">25dp</dimen>
|
||||
<dimen name="setting_end_padding">10dp</dimen>
|
||||
<dimen name="setting_vertical_padding">10dp</dimen>
|
||||
<dimen name="setting_end_font_width">60dp</dimen>
|
||||
<dimen name="setting_start_image_width">20dp</dimen>
|
||||
<dimen name="size_button">18sp</dimen>
|
||||
<dimen name="btn_top_bottom_padding">10dp</dimen>
|
||||
<dimen name="btn_height">50dp</dimen>
|
||||
|
||||
<dimen name="float_size">60dp</dimen>
|
||||
<dimen name="float_margin_start">50dp</dimen>
|
||||
<dimen name="float_stand_size">36dp</dimen>
|
||||
|
||||
<dimen name="setting_start_font_size">15sp</dimen>
|
||||
<dimen name="setting_end_font_size">13sp</dimen>
|
||||
</resources>
|
||||
3
floatwindow/src/main/res/values/strings.xml
Normal file
@@ -0,0 +1,3 @@
|
||||
<resources>
|
||||
<string name="app_name">floatwindow</string>
|
||||
</resources>
|
||||