我想制作一个浮动动作按钮,例如facebook Messenger按钮,该按钮可以覆盖其他应用程序并执行特定的工作,我在清单中获得了许可,但该应用程序仍然崩溃。
清单权限
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:name=".view_model.FloatImage"
android:theme="@style/AppTheme">
<activity
android:name=".view.MainActivity"
android:label="@string/title_activity_main"
android:theme="@style/AppTheme.NoActionBar">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service android:name=".model.FloatingCircle" />
</application>
</manifest>
这是我的浮动按钮课程
public void onCreate() {
super.onCreate();
initializeView();
getScreenSize();
showFloat();
}
@SuppressLint("ClickableViewAccessibility")
private void showFloat() {
_closeParams = new WindowManager.LayoutParams(
WindowManager.LayoutParams.WRAP_CONTENT,
WindowManager.LayoutParams.WRAP_CONTENT,
WindowManager.LayoutParams.TYPE_PHONE,
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
PixelFormat.TRANSLUCENT);
_closeParams.gravity = Gravity.BOTTOM | Gravity.CENTER;
_closeParams.x = 0;
_closeParams.y = 100;
myParams = new WindowManager.LayoutParams(
(int) (0.18 * screen_width),
(int) (0.18 * screen_width),
WindowManager.LayoutParams.TYPE_PHONE,
WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED
| WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS
| WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
PixelFormat.TRANSLUCENT
);
myParams.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN;
myParams.x = screen_width / 2; // horizontal center for the image
myParams.y = 0;
// myParams.screenOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
if (Build.VERSION.SDK_INT >= 23) {
if (Settings.canDrawOverlays(context)) {
if (!smallCircle.isShown()) {
windowManager.addView(smallCircle, myParams);
windowManagerClose.addView(layout, _closeParams);
layout.setVisibility(View.INVISIBLE);
close.startAnimation(shake);
}
}
} else {
if (!smallCircle.isShown()) {
windowManager.addView(smallCircle, myParams);
windowManagerClose.addView(layout, _closeParams);
layout.setVisibility(View.INVISIBLE);
close.startAnimation(shake);
}
}
try {
// for moving the picture on touch and slide
smallCircle.setOnTouchListener(new View.OnTouchListener() {
public WindowManager.LayoutParams myParams2;
private int initialX;
private int initialY;
private float initialTouchX;
private float initialTouchY;
@Override
public boolean onTouch(View v, final MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
initialX = myParams.x;
initialY = myParams.y;
initialTouchX = event.getRawX();
initialTouchY = event.getRawY();
animator.stop();
break;
case MotionEvent.ACTION_UP:
if (MathUtil.betweenExclusive(myParams.x, -100, 100) && !MathUtil.betweenExclusive(myParams.y, screen_height / 3, screen_height / 2)) {
//moving to center range of screen
animator.start(screen_width / 2, myParams.y);
android.view.ViewGroup.LayoutParams layoutParams = smallCircle.getLayoutParams();
layoutParams.width = (int) (0.18 * screen_width);
layoutParams.height = (int) (0.18 * screen_width);
smallCircle.setLayoutParams(layoutParams);
windowManager.updateViewLayout(v, myParams);
layout.setVisibility(View.INVISIBLE);
} else if (MathUtil.betweenExclusive((int) event.getRawX(), 0, screen_width / 5)) {
//move to left of screen
if (MathUtil.betweenExclusive((int) event.getRawY(), 0, screen_height / 10)) {
// myParams.y = 0 ;
animator.start(-screen_width / 2, -((screen_height / 2) - 150));
android.view.ViewGroup.LayoutParams layoutParams = smallCircle.getLayoutParams();
layoutParams.width = (int) (0.18 * screen_width);
layoutParams.height = (int) (0.18 * screen_width);
smallCircle.setLayoutParams(layoutParams);
windowManager.updateViewLayout(v, myParams);
layout.setVisibility(View.INVISIBLE);
} else if (MathUtil.betweenExclusive((int) event.getRawY(), 9 * (screen_height / 10), screen_height)) {
animator.start(-screen_width / 2, screen_height / 2 - 150);
android.view.ViewGroup.LayoutParams layoutParams = smallCircle.getLayoutParams();
layoutParams.width = (int) (0.18 * screen_width);
layoutParams.height = (int) (0.18 * screen_width);
smallCircle.setLayoutParams(layoutParams);
windowManager.updateViewLayout(v, myParams);
layout.setVisibility(View.INVISIBLE);
} else {
animator.start(-screen_width / 2, myParams.y);
android.view.ViewGroup.LayoutParams layoutParams = smallCircle.getLayoutParams();
layoutParams.width = (int) (0.18 * screen_width);
layoutParams.height = (int) (0.18 * screen_width);
smallCircle.setLayoutParams(layoutParams);
windowManager.updateViewLayout(v, myParams);
layout.setVisibility(View.INVISIBLE);
}
} else if (MathUtil.betweenExclusive((int) event.getRawX(), screen_width - (screen_width / 5), screen_width)) {
//move to right of screen
if (MathUtil.betweenExclusive((int) event.getRawY(), 0, screen_height / 10)) {
// myParams.y = 0 ;
animator.start(screen_width / 2, -((screen_height / 2) - 150));
android.view.ViewGroup.LayoutParams layoutParams = smallCircle.getLayoutParams();
layoutParams.width = (int) (0.18 * screen_width);
layoutParams.height = (int) (0.18 * screen_width);
smallCircle.setLayoutParams(layoutParams);
windowManager.updateViewLayout(v, myParams);
layout.setVisibility(View.INVISIBLE);
} else if (MathUtil.betweenExclusive((int) event.getRawY(), 9 * (screen_height / 10), screen_height)) {
animator.start(screen_width / 2, screen_height / 2 - 150);
android.view.ViewGroup.LayoutParams layoutParams = smallCircle.getLayoutParams();
layoutParams.width = (int) (0.18 * screen_width);
layoutParams.height = (int) (0.18 * screen_width);
smallCircle.setLayoutParams(layoutParams);
windowManager.updateViewLayout(v, myParams);
layout.setVisibility(View.INVISIBLE);
} else {
animator.start(screen_width / 2, myParams.y);
android.view.ViewGroup.LayoutParams layoutParams = smallCircle.getLayoutParams();
layoutParams.width = (int) (0.18 * screen_width);
layoutParams.height = (int) (0.18 * screen_width);
smallCircle.setLayoutParams(layoutParams);
windowManager.updateViewLayout(v, myParams);
layout.setVisibility(View.INVISIBLE);
}
} else if (MathUtil.betweenExclusive((int) event.getRawX(), screen_width / 5, 2 * (screen_width / 5))) {
//move to left of screen
if (MathUtil.betweenExclusive((int) event.getRawY(), 0, screen_height / 10)) {
animator.start(-screen_width / 2, -((screen_height / 2) - 150));
android.view.ViewGroup.LayoutParams layoutParams = smallCircle.getLayoutParams();
layoutParams.width = (int) (0.18 * screen_width);
layoutParams.height = (int) (0.18 * screen_width);
smallCircle.setLayoutParams(layoutParams);
windowManager.updateViewLayout(v, myParams);
layout.setVisibility(View.INVISIBLE);
} else if (MathUtil.betweenExclusive((int) event.getRawY(), 9 * (screen_height / 10), screen_height)) {
animator.start(-screen_width / 2, screen_height / 2 - 150);
android.view.ViewGroup.LayoutParams layoutParams = smallCircle.getLayoutParams();
layoutParams.width = (int) (0.18 * screen_width);
layoutParams.height = (int) (0.18 * screen_width);
smallCircle.setLayoutParams(layoutParams);
windowManager.updateViewLayout(v, myParams);
layout.setVisibility(View.INVISIBLE);
} else {
animator.start(-screen_width / 2, myParams.y);
android.view.ViewGroup.LayoutParams layoutParams = smallCircle.getLayoutParams();
layoutParams.width = (int) (0.18 * screen_width);
layoutParams.height = (int) (0.18 * screen_width);
smallCircle.setLayoutParams(layoutParams);
windowManager.updateViewLayout(v, myParams);
layout.setVisibility(View.INVISIBLE);
}
} else if (MathUtil.betweenExclusive((int) event.getRawX(), 3 * (screen_width / 5), screen_width)) {
//move to right of screen
if (MathUtil.betweenExclusive((int) event.getRawY(), 0, screen_height / 10)) {
// myParams.y = 0 ;
animator.start(screen_width / 2, -((screen_height / 2) - 150));
android.view.ViewGroup.LayoutParams layoutParams = smallCircle.getLayoutParams();
layoutParams.width = (int) (0.18 * screen_width);
layoutParams.height = (int) (0.18 * screen_width);
smallCircle.setLayoutParams(layoutParams);
windowManager.updateViewLayout(v, myParams);
layout.setVisibility(View.INVISIBLE);
} else if (MathUtil.betweenExclusive((int) event.getRawY(), 9 * (screen_height / 10), screen_height)) {
animator.start(screen_width / 2, screen_height / 2 - 150);
android.view.ViewGroup.LayoutParams layoutParams = smallCircle.getLayoutParams();
layoutParams.width = (int) (0.18 * screen_width);
layoutParams.height = (int) (0.18 * screen_width);
smallCircle.setLayoutParams(layoutParams);
windowManager.updateViewLayout(v, myParams);
layout.setVisibility(View.INVISIBLE);
} else {
animator.start(screen_width / 2, myParams.y);
android.view.ViewGroup.LayoutParams layoutParams = smallCircle.getLayoutParams();
layoutParams.width = (int) (0.18 * screen_width);
layoutParams.height = (int) (0.18 * screen_width);
smallCircle.setLayoutParams(layoutParams);
windowManager.updateViewLayout(v, myParams);
layout.setVisibility(View.INVISIBLE);
}
} else if (MathUtil.betweenExclusive(myParams.x, -50, 50) && MathUtil.betweenExclusive(myParams.y, screen_height / 3, screen_height / 2)) {
Visibility();
stopSelf();
} else {
//not in either of the above cases
animator.start(screen_width / 2, myParams.y);
android.view.ViewGroup.LayoutParams layoutParams = smallCircle.getLayoutParams();
layoutParams.width = (int) (0.18 * screen_width);
layoutParams.height = (int) (0.18 * screen_width);
smallCircle.setLayoutParams(layoutParams);
windowManager.updateViewLayout(v, myParams);
layout.setVisibility(View.INVISIBLE);
}
break;
case MotionEvent.ACTION_MOVE:
layout.setVisibility(View.VISIBLE);
myParams.x = initialX + (int) (event.getRawX() - initialTouchX);
myParams.y = initialY + (int) (event.getRawY() - initialTouchY);
windowManager.updateViewLayout(v, myParams);
if (MathUtil.betweenExclusive((int) event.getRawX(), 0, screen_width / 5) || MathUtil.betweenExclusive((int) event.getRawX(), screen_width - (screen_width / 5), screen_width)) {
android.view.ViewGroup.LayoutParams layoutParams = smallCircle.getLayoutParams();
layoutParams.width = (int) (0.18 * screen_width);
layoutParams.height = (int) (0.18 * screen_width);
smallCircle.setLayoutParams(layoutParams);
windowManager.updateViewLayout(v, myParams);
} else if (MathUtil.betweenExclusive((int) event.getRawX(), 2 * (screen_width / 5), 3 * (screen_width / 5))) {
android.view.ViewGroup.LayoutParams layoutParams = smallCircle.getLayoutParams();
layoutParams.width = (int) (0.18 * screen_width) + 100 + 100;
layoutParams.height = (int) (0.18 * screen_width) + 100 + 100;
smallCircle.setLayoutParams(layoutParams);
windowManager.updateViewLayout(v, myParams);
} else if (MathUtil.betweenExclusive((int) event.getRawX(), screen_width / 5, 2 * (screen_width / 5)) || MathUtil.betweenExclusive((int) event.getRawX(), 3 * (screen_width / 5), screen_width)) {
android.view.ViewGroup.LayoutParams layoutParams = smallCircle.getLayoutParams();
layoutParams.width = (int) (0.18 * screen_width) + 100;
layoutParams.height = (int) (0.18 * screen_width) + 100;
smallCircle.setLayoutParams(layoutParams);
windowManager.updateViewLayout(v, myParams);
}
break;
}
return true;
}
});
} catch (Exception e) {
}
}
private void Visibility() {
if (windowManager != null) {
windowManager.removeViewImmediate(smallCircle);
windowManagerClose.removeViewImmediate(layout);
}
}
private void initializeView() {
windowManager = (WindowManager) getSystemService(WINDOW_SERVICE);
windowManagerClose = (WindowManager) getSystemService(WINDOW_SERVICE);
smallCircle = new ImageView(this);
smallCircle.setImageResource(R.mipmap.dummy);
close = new ImageView(this);
close.setImageResource(R.mipmap._close);
context = FloatingCircle.this;
shake = AnimationUtils.loadAnimation(getApplicationContext(), R.anim.wiggle);
shake.setRepeatCount(Animation.INFINITE);
layout = new LinearLayout(this);
layout.addView(close);
animator = new MoveAnimator();
}
private void getScreenSize() {
Display display = windowManager.getDefaultDisplay();
Point size = new Point();
display.getSize(size);
screen_width = size.x;
screen_height = size.y;
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}
private static class MathUtil {
public static boolean betweenExclusive(int x, int min, int max) {
return x > min && x < max;
}
}
//this class is written to move the image to either corners if touch_up
private class MoveAnimator implements Runnable {
private Handler handler = new Handler(Looper.getMainLooper());
private float destinationX;
private float destinationY;
private long startingTime;
private void start(float x, float y) {
this.destinationX = x;
this.destinationY = y;
startingTime = System.currentTimeMillis();
handler.post(this);
}
@Override
public void run() {
if (smallCircle != null && smallCircle.getParent() != null) {
float progress = Math.min(1, (System.currentTimeMillis() - startingTime) / 400f);
float deltaX = (destinationX - myParams.x) * progress;
float deltaY = (destinationY - myParams.y) * progress;
move(deltaX, deltaY);
if (progress < 1) {
handler.post(this);
}
}
}
private void stop() {
handler.removeCallbacks(this);
}
}
protected void move(float deltaX, float deltaY) {
myParams.x += deltaX;
myParams.y += deltaY;
windowManager.updateViewLayout(smallCircle, myParams);
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Visibility();
_closeParams = new WindowManager.LayoutParams(
WindowManager.LayoutParams.WRAP_CONTENT,
WindowManager.LayoutParams.WRAP_CONTENT,
WindowManager.LayoutParams.TYPE_PHONE,
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
PixelFormat.TRANSLUCENT);
_closeParams.gravity = Gravity.BOTTOM | Gravity.CENTER;
_closeParams.x = 0;
_closeParams.y = 100;
myParams = new WindowManager.LayoutParams(
(int) (0.18 * screen_width),
(int) (0.18 * screen_width),
WindowManager.LayoutParams.TYPE_PHONE,
WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED
| WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS
| WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
PixelFormat.TRANSLUCENT
);
myParams.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN;
myParams.x = screen_width / 2; // horizontal center for the image
myParams.y = 0;
windowManager.addView(smallCircle, myParams);
windowManagerClose.addView(layout, _closeParams);
layout.setVisibility(View.INVISIBLE);
close.startAnimation(shake);
return START_STICKY; //system will try to recreate the service if in case its killed
}
这是我的主要活动
FloatingActionButton fab = findViewById(R.id.fab);
fab.setOnClickListener(new View.OnClickListener() {
@RequiresApi(api = Build.VERSION_CODES.M)
@Override
public void onClick(View view) {
//add the service here
//make the button gone
if ((Build.VERSION.SDK_INT >= 23)) {
if (!Settings.canDrawOverlays(context)) {
Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION,
Uri.parse("package:" + getPackageName()));
startActivityForResult(intent, OVERLAY_PERMISSION_REQ_CODE);
} else if (Settings.canDrawOverlays(context)) {
startService(new Intent(context, FloatingCircle.class));
}
}
else
{
startService(new Intent(context, FloatingCircle.class));
}
}
});
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == OVERLAY_PERMISSION_REQ_CODE) {
startService(new Intent(context, FloatingCircle.class));
}
}
这是我的Logcat错误
2019-03-05 15:45:19.086 31841-31851 /? E / zygote64:发送失败 回复调试器:管道损坏 2019-03-05 15:45:20.401 31841-31841 / com.anam.floatimage E / WindowManager:BadTokenException或InvalidDisplayException,干净 起来 2019-03-05 15:45:20.403 31841-31841 / com.anam.floatimage E / Android运行时:致命异常:主要 流程:com.anam.floatimage,PID:31841 java.lang.RuntimeException:无法创建服务com.anam.floatimage.model.FloatingCircle: android.view.WindowManager $ BadTokenException:无法添加窗口 android.view.ViewRootImpl$W@5ccfc1d-窗口权限被拒绝 2002型 在android.app.ActivityThread.handleCreateService(ActivityThread.java:3385) 在android.app.ActivityThread.-wrap4(未知来源:0) 在android.app.ActivityThread $ H.handleMessage(ActivityThread.java:1703) 在android.os.Handler.dispatchMessage(Handler.java:106) 在android.os.Looper.loop(Looper.java:176) 在android.app.ActivityThread.main(ActivityThread.java:6635) 在java.lang.reflect.Method.invoke(本机方法) 在com.android.internal.os.RuntimeInit $ MethodAndArgsCaller.run(RuntimeInit.java:547) 在com.android.internal.os.ZygoteInit.main(ZygoteInit.java:823) 原因:android.view.WindowManager $ BadTokenException:无法添加窗口android.view.ViewRootImpl$W@5ccfc1d-权限 窗口类型2002拒绝 在android.view.ViewRootImpl.setView(ViewRootImpl.java:820) 在android.view.WindowManagerGlobal.addView(WindowManagerGlobal.java:356) 在android.view.WindowManagerImpl.addView(WindowManagerImpl.java:94) 在com.anam.floatimage.model.FloatingCircle.showFloat(FloatingCircle.java:86) 在com.anam.floatimage.model.FloatingCircle.onCreate(FloatingCircle.java:50) 在android.app.ActivityThread.handleCreateService(ActivityThread.java:3375) 在android.app.ActivityThread.-wrap4(未知来源:0) 在android.app.ActivityThread $ H.handleMessage(ActivityThread.java:1703) 在android.os.Handler.dispatchMessage(Handler.java:106) 在android.os.Looper.loop(Looper.java:176) 在android.app.ActivityThread.main(ActivityThread.java:6635) 在java.lang.reflect.Method.invoke(本机方法) 在com.android.internal.os.RuntimeInit $ MethodAndArgsCaller.run(RuntimeInit.java:547) 在com.android.internal.os.ZygoteInit.main(ZygoteInit.java:823)