android - 为什么在 android mobile version 8.1 [oreo] Floating Widget 服务不工作?[应用程序越来越崩溃]
问题描述
我在浮动小部件服务图标中工作,代码在 android 版本 6.1 之前工作正常,我能够在发送通知时从服务器获取通知图标。
但是在 android 版本 8.1 中对其进行测试时,当从服务器发送通知时,应用程序会崩溃,但我无法找到解决方案。我不知道为什么会发生这种情况。
LOGCAT
beginning of crash
2019-03-02 11:41:21.416 12616-12616/com.progressive_solution.parttimeforce E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.progressive_solution.parttimeforce, PID: 12616
java.lang.RuntimeException: Unable to create service com.progressive_solution.parttimeforce.FloatingWidgetService: android.view.WindowManager$BadTokenException: Unable to add window android.view.ViewRootImpl$W@ac5309 -- permission denied for window type 2002
at android.app.ActivityThread.handleCreateService(ActivityThread.java:3568)
at android.app.ActivityThread.-wrap4(Unknown Source:0)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1812)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:164)
at android.app.ActivityThread.main(ActivityThread.java:7000)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:441)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1408)
Caused by: android.view.WindowManager$BadTokenException: Unable to add window android.view.ViewRootImpl$W@ac5309 -- permission denied for window type 2002
at android.view.ViewRootImpl.setView(ViewRootImpl.java:1026)
at android.view.WindowManagerGlobal.addView(WindowManagerGlobal.java:384)
at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:101)
at com.progressive_solution.parttimeforce.FloatingWidgetService.addRemoveView(FloatingWidgetService.java:86)
at com.progressive_solution.parttimeforce.FloatingWidgetService.onCreate(FloatingWidgetService.java:58)
at android.app.ActivityThread.handleCreateService(ActivityThread.java:3558)
at android.app.ActivityThread.-wrap4(Unknown Source:0)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1812)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:164)
at android.app.ActivityThread.main(ActivityThread.java:7000)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:441)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1408)
我的密码
FloatingWidgetService.java
public class FloatingWidgetService extends Service implements View.OnClickListener
{
private WindowManager mWindowManager;
private View mFloatingWidgetView, collapsedView, expandedView;
private ImageView remove_image_view;
private Point szWindow = new Point();
private View removeFloatingWidgetView;
private int x_init_cord, y_init_cord, x_init_margin, y_init_margin;
//Variable to check if the Floating widget view is on left side or in right side
// initially we are displaying Floating widget view to Left side so set it to true
private boolean isLeft = true;
public FloatingWidgetService() {
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public void onCreate() {
super.onCreate();
//init WindowManager
mWindowManager = (WindowManager) getSystemService(WINDOW_SERVICE);
getWindowManagerDefaultDisplay();
//Init LayoutInflater
LayoutInflater inflater = (LayoutInflater) getSystemService(LAYOUT_INFLATER_SERVICE);
addRemoveView(inflater);
addFloatingWidgetView(inflater);
implementClickListeners();
implementTouchListenerToFloatingWidgetView();
}
/* Add Remove View to Window Manager */
private View addRemoveView(LayoutInflater inflater) {
//Inflate the removing view layout we created
removeFloatingWidgetView = inflater.inflate(R.layout.remove_floating_widget_layout, null);
//Add the view to the window.
WindowManager.LayoutParams paramRemove = new WindowManager.LayoutParams(
WindowManager.LayoutParams.WRAP_CONTENT,
WindowManager.LayoutParams.WRAP_CONTENT,
WindowManager.LayoutParams.TYPE_PHONE,
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH | WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS,
PixelFormat.TRANSLUCENT);
//Specify the view position
paramRemove.gravity = Gravity.TOP | Gravity.LEFT;
//Initially the Removing widget view is not visible, so set visibility to GONE
removeFloatingWidgetView.setVisibility(View.GONE);
remove_image_view = (ImageView) removeFloatingWidgetView.findViewById(R.id.remove_img);
//Add the view to the window
mWindowManager.addView(removeFloatingWidgetView, paramRemove);
return remove_image_view;
}
/* Add Floating Widget View to Window Manager */
private void addFloatingWidgetView(LayoutInflater inflater) {
//Inflate the floating view layout we created
mFloatingWidgetView = inflater.inflate(R.layout.activity_floating_widget_service, null);
//Add the view to the window.
final WindowManager.LayoutParams params = new WindowManager.LayoutParams(
WindowManager.LayoutParams.WRAP_CONTENT,
WindowManager.LayoutParams.WRAP_CONTENT,
WindowManager.LayoutParams.TYPE_PHONE,
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
PixelFormat.TRANSLUCENT);
//Specify the view position
params.gravity = Gravity.TOP | Gravity.LEFT;
//Initially view will be added to top-left corner, you change x-y coordinates according to your need
params.x = 0;
params.y = 100;
//Add the view to the window
mWindowManager.addView(mFloatingWidgetView, params);
//find id of collapsed view layout
collapsedView = mFloatingWidgetView.findViewById(R.id.collapse_view);
//find id of the expanded view layout
expandedView = mFloatingWidgetView.findViewById(R.id.expanded_container);
}
private void getWindowManagerDefaultDisplay() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR2)
mWindowManager.getDefaultDisplay().getSize(szWindow);
else {
int w = mWindowManager.getDefaultDisplay().getWidth();
int h = mWindowManager.getDefaultDisplay().getHeight();
szWindow.set(w, h);
}
}
/* Implement Touch Listener to Floating Widget Root View */
private void implementTouchListenerToFloatingWidgetView() {
//Drag and move floating view using user's touch action.
mFloatingWidgetView.findViewById(R.id.root_container).setOnTouchListener(new View.OnTouchListener() {
long time_start = 0, time_end = 0;
boolean isLongClick = false;//variable to judge if user click long press
boolean inBounded = false;//variable to judge if floating view is bounded to remove view
int remove_img_width = 0, remove_img_height = 0;
Handler handler_longClick = new Handler();
Runnable runnable_longClick = new Runnable() {
@Override
public void run() {
//On Floating Widget Long Click
//Set isLongClick as true
isLongClick = true;
//Set remove widget view visibility to VISIBLE
removeFloatingWidgetView.setVisibility(View.VISIBLE);
onFloatingWidgetLongClick();
}
};
@Override
public boolean onTouch(View v, MotionEvent event) {
//Get Floating widget view params
WindowManager.LayoutParams layoutParams = (WindowManager.LayoutParams) mFloatingWidgetView.getLayoutParams();
//get the touch location coordinates
int x_cord = (int) event.getRawX();
int y_cord = (int) event.getRawY();
int x_cord_Destination, y_cord_Destination;
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
time_start = System.currentTimeMillis();
handler_longClick.postDelayed(runnable_longClick, 600);
remove_img_width = remove_image_view.getLayoutParams().width;
remove_img_height = remove_image_view.getLayoutParams().height;
x_init_cord = x_cord;
y_init_cord = y_cord;
//remember the initial position.
x_init_margin = layoutParams.x;
y_init_margin = layoutParams.y;
return true;
case MotionEvent.ACTION_UP:
isLongClick = false;
removeFloatingWidgetView.setVisibility(View.GONE);
remove_image_view.getLayoutParams().height = remove_img_height;
remove_image_view.getLayoutParams().width = remove_img_width;
handler_longClick.removeCallbacks(runnable_longClick);
//If user drag and drop the floating widget view into remove view then stop the service
if (inBounded) {
stopSelf();
inBounded = false;
break;
}
//Get the difference between initial coordinate and current coordinate
int x_diff = x_cord - x_init_cord;
int y_diff = y_cord - y_init_cord;
//The check for x_diff <5 && y_diff< 5 because sometime elements moves a little while clicking.
//So that is click event.
if (Math.abs(x_diff) < 5 && Math.abs(y_diff) < 5) {
time_end = System.currentTimeMillis();
//Also check the difference between start time and end time should be less than 300ms
if ((time_end - time_start) < 300)
onFloatingWidgetClick();
}
y_cord_Destination = y_init_margin + y_diff;
int barHeight = getStatusBarHeight();
if (y_cord_Destination < 0) {
y_cord_Destination = 0;
} else if (y_cord_Destination + (mFloatingWidgetView.getHeight() + barHeight) > szWindow.y) {
y_cord_Destination = szWindow.y - (mFloatingWidgetView.getHeight() + barHeight);
}
layoutParams.y = y_cord_Destination;
inBounded = false;
//reset position if user drags the floating view
resetPosition(x_cord);
return true;
case MotionEvent.ACTION_MOVE:
int x_diff_move = x_cord - x_init_cord;
int y_diff_move = y_cord - y_init_cord;
x_cord_Destination = x_init_margin + x_diff_move;
y_cord_Destination = y_init_margin + y_diff_move;
//If user long click the floating view, update remove view
if (isLongClick) {
int x_bound_left = szWindow.x / 2 - (int) (remove_img_width * 1.5);
int x_bound_right = szWindow.x / 2 + (int) (remove_img_width * 1.5);
int y_bound_top = szWindow.y - (int) (remove_img_height * 1.5);
//If Floating view comes under Remove View update Window Manager
if ((x_cord >= x_bound_left && x_cord <= x_bound_right) && y_cord >= y_bound_top) {
inBounded = true;
int x_cord_remove = (int) ((szWindow.x - (remove_img_height * 1.5)) / 2);
int y_cord_remove = (int) (szWindow.y - ((remove_img_width * 1.5) + getStatusBarHeight()));
if (remove_image_view.getLayoutParams().height == remove_img_height) {
remove_image_view.getLayoutParams().height = (int) (remove_img_height * 1.5);
remove_image_view.getLayoutParams().width = (int) (remove_img_width * 1.5);
WindowManager.LayoutParams param_remove = (WindowManager.LayoutParams) removeFloatingWidgetView.getLayoutParams();
param_remove.x = x_cord_remove;
param_remove.y = y_cord_remove;
mWindowManager.updateViewLayout(removeFloatingWidgetView, param_remove);
}
layoutParams.x = x_cord_remove + (Math.abs(removeFloatingWidgetView.getWidth() - mFloatingWidgetView.getWidth())) / 2;
layoutParams.y = y_cord_remove + (Math.abs(removeFloatingWidgetView.getHeight() - mFloatingWidgetView.getHeight())) / 2;
//Update the layout with new X & Y coordinate
mWindowManager.updateViewLayout(mFloatingWidgetView, layoutParams);
break;
} else {
//If Floating window gets out of the Remove view update Remove view again
inBounded = false;
remove_image_view.getLayoutParams().height = remove_img_height;
remove_image_view.getLayoutParams().width = remove_img_width;
onFloatingWidgetClick();
}
}
layoutParams.x = x_cord_Destination;
layoutParams.y = y_cord_Destination;
//Update the layout with new X & Y coordinate
mWindowManager.updateViewLayout(mFloatingWidgetView, layoutParams);
return true;
}
return false;
}
});
}
private void implementClickListeners() {
mFloatingWidgetView.findViewById(R.id.close_floating_view).setOnClickListener(this);
mFloatingWidgetView.findViewById(R.id.close_expanded_view).setOnClickListener(this);
mFloatingWidgetView.findViewById(R.id.open_activity_button).setOnClickListener(this);
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.close_floating_view:
//close the service and remove the from from the window
stopSelf();
break;
case R.id.close_expanded_view:
collapsedView.setVisibility(View.VISIBLE);
expandedView.setVisibility(View.GONE);
break;
case R.id.open_activity_button:
//open the activity and stop service
Intent intent = new Intent(FloatingWidgetService.this, Get_Permission.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
//close the service and remove view from the view hierarchy
stopSelf();
break;
}
}
/* on Floating Widget Long Click, increase the size of remove view as it look like taking focus */
private void onFloatingWidgetLongClick() {
//Get remove Floating view params
WindowManager.LayoutParams removeParams = (WindowManager.LayoutParams) removeFloatingWidgetView.getLayoutParams();
//get x and y coordinates of remove view
int x_cord = (szWindow.x - removeFloatingWidgetView.getWidth()) / 2;
int y_cord = szWindow.y - (removeFloatingWidgetView.getHeight() + getStatusBarHeight());
removeParams.x = x_cord;
removeParams.y = y_cord;
//Update Remove view params
mWindowManager.updateViewLayout(removeFloatingWidgetView, removeParams);
}
/* Reset position of Floating Widget view on dragging */
private void resetPosition(int x_cord_now) {
if (x_cord_now <= szWindow.x / 2) {
isLeft = true;
moveToLeft(x_cord_now);
} else {
isLeft = false;
moveToRight(x_cord_now);
}
}
/* Method to move the Floating widget view to Left */
private void moveToLeft(final int current_x_cord) {
final int x = szWindow.x - current_x_cord;
new CountDownTimer(500, 5) {
//get params of Floating Widget view
WindowManager.LayoutParams mParams = (WindowManager.LayoutParams) mFloatingWidgetView.getLayoutParams();
public void onTick(long t) {
long step = (500 - t) / 5;
mParams.x = 0 - (int) (current_x_cord * current_x_cord * step);
//If you want bounce effect uncomment below line and comment above line
// mParams.x = 0 - (int) (double) bounceValue(step, x);
//Update window manager for Floating Widget
mWindowManager.updateViewLayout(mFloatingWidgetView, mParams);
}
public void onFinish() {
mParams.x = 0;
//Update window manager for Floating Widget
mWindowManager.updateViewLayout(mFloatingWidgetView, mParams);
}
}.start();
}
/* Method to move the Floating widget view to Right */
private void moveToRight(final int current_x_cord) {
new CountDownTimer(500, 5) {
//get params of Floating Widget view
WindowManager.LayoutParams mParams = (WindowManager.LayoutParams) mFloatingWidgetView.getLayoutParams();
public void onTick(long t) {
long step = (500 - t) / 5;
mParams.x = (int) (szWindow.x + (current_x_cord * current_x_cord * step) - mFloatingWidgetView.getWidth());
//If you want bounce effect uncomment below line and comment above line
// mParams.x = szWindow.x + (int) (double) bounceValue(step, x_cord_now) - mFloatingWidgetView.getWidth();
//Update window manager for Floating Widget
mWindowManager.updateViewLayout(mFloatingWidgetView, mParams);
}
public void onFinish() {
mParams.x = szWindow.x - mFloatingWidgetView.getWidth();
//Update window manager for Floating Widget
mWindowManager.updateViewLayout(mFloatingWidgetView, mParams);
}
}.start();
}
/* Get Bounce value if you want to make bounce effect to your Floating Widget */
private double bounceValue(long step, long scale) {
double value = scale * java.lang.Math.exp(-0.055 * step) * java.lang.Math.cos(0.08 * step);
return value;
}
/* Detect if the floating view is collapsed or expanded */
private boolean isViewCollapsed() {
return mFloatingWidgetView == null || mFloatingWidgetView.findViewById(R.id.collapse_view).getVisibility() == View.VISIBLE;
}
/* return status bar height on basis of device display metrics */
private int getStatusBarHeight() {
return (int) Math.ceil(25 * getApplicationContext().getResources().getDisplayMetrics().density);
}
/* Update Floating Widget view coordinates on Configuration change */
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
getWindowManagerDefaultDisplay();
WindowManager.LayoutParams layoutParams = (WindowManager.LayoutParams) mFloatingWidgetView.getLayoutParams();
if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) {
if (layoutParams.y + (mFloatingWidgetView.getHeight() + getStatusBarHeight()) > szWindow.y) {
layoutParams.y = szWindow.y - (mFloatingWidgetView.getHeight() + getStatusBarHeight());
mWindowManager.updateViewLayout(mFloatingWidgetView, layoutParams);
}
if (layoutParams.x != 0 && layoutParams.x < szWindow.x) {
resetPosition(szWindow.x);
}
} else if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT) {
if (layoutParams.x > szWindow.x) {
resetPosition(szWindow.x);
}
}
}
/* on Floating widget click show expanded view */
private void onFloatingWidgetClick() {
if (isViewCollapsed()) {
//When user clicks on the image view of the collapsed layout,
//visibility of the collapsed layout will be changed to "View.GONE"
//and expanded view will become visible.
collapsedView.setVisibility(View.GONE);
expandedView.setVisibility(View.VISIBLE);
}
}
@Override
public void onDestroy() {
super.onDestroy();
/* on destroy remove both view from window manager */
if (mFloatingWidgetView != null)
mWindowManager.removeView(mFloatingWidgetView);
if (removeFloatingWidgetView != null)
mWindowManager.removeView(removeFloatingWidgetView);
}
}
权限检查.java
private void writeCalendarEvent()
{
Log.d(Utils.LogTag, "lst_StartService -> Utils.canDrawOverlays(Main.this): " + Utils.canDrawOverlays(Permissioncheck.this));
if(Utils.canDrawOverlays(Permissioncheck.this))
{
checkPermission_Contact();
startService();
}
else
{
requestPermission(OVERLAY_PERMISSION_REQ_CODE_CHATHEAD);
}
}
public void startService()
{
boolean results = checkPermission_Contact();
if (results)
{
Intent k = new Intent(context, Login.class);
startActivity(k);
}
}
private void needPermissionDialog(final int requestCode)
{
android.app.AlertDialog.Builder builder = new android.app.AlertDialog.Builder(Permissioncheck.this);
builder.setMessage("You need to allow permission");
builder.setPositiveButton("OK",
new android.content.DialogInterface.OnClickListener()
{
@Override
public void onClick(DialogInterface dialog, int which)
{
// TODO Auto-generated method stub
requestPermission(requestCode);
}
});
builder.setNegativeButton("Cancel", new android.content.DialogInterface.OnClickListener()
{
@Override
public void onClick(DialogInterface dialog, int which)
{
// TODO Auto-generated method stub
}
});
builder.setCancelable(false);
builder.show();
}
@Override
protected void onResume()
{
// TODO Auto-generated method stub
super.onResume();
}
private void requestPermission(int requestCode)
{
Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION);
intent.setData(Uri.parse("package:" + getPackageName()));
startActivityForResult(intent, requestCode);
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data)
{
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == OVERLAY_PERMISSION_REQ_CODE_CHATHEAD)
{
if (!Utils.canDrawOverlays(Permissioncheck.this))
{
needPermissionDialog(requestCode);
} else
{
startService();
}
}
}
帮我解决问题。
解决方案
添加WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY
参考
推荐阅读
- javascript - 我的下拉菜单未正确激活
- haskell - 将数据类型定义为 MonadSample
- javascript - 如何移动插入符号 «home» 或 «end» 使用 fn+箭头键 JavaScript
- python - 如何将夹具作为参数传递给另一个夹具
- reactjs - 自定义库组件在智能感知上不显示所需的道具
- sql - 在 MS Access Query 中使用来自三个未绑定的不同组合框的三个条件
- javascript - Node.js - 不和谐拥抱命令 - 用户特定不起作用
- javascript - 如何/何时删除子元素以清除搜索结果?
- cassandra - 从 comments_by_video 选择评论 WHERE uuid = 'with id 357c33b4-9054-a5e1-8da8-d9e38294fac1';
- google-apps-script - 谷歌工作表 - 根据条件将数据复制到另一个选项卡