AccessibilityService 覆盖的 WindowManagerBadTokenException
WindowManagerBadTokenException for AccessibilityService Overlay
我正在使用 Xamarin 和 Visual Studio 创建无障碍服务,遵循此 Codelab (Java + Android SDK):https://codelabs.developers.google.com/codelabs/developing-android-a11y-service/#0
无障碍服务已启动,运行 可以在我的 android 设备的“设置”>“无障碍”中找到它。
服务:
[Service(Label = "Input Utility", Permission = Manifest.Permission.BindAccessibilityService)]
[IntentFilter(new string[] { "android.accessibilityservice.AccessibilityService" })]
[MetaData("android.accessibilityservice", Resource = "@xml/config")]
public class TapService : AccessibilityService
{
FrameLayout mLayout;
public override void OnAccessibilityEvent(AccessibilityEvent e)
{
}
public override void OnInterrupt()
{
}
public override bool OnUnbind(Intent intent)
{
return base.OnUnbind(intent);
}
protected override void OnServiceConnected()
{
base.OnServiceConnected();
IWindowManager wm = Application.Context.GetSystemService(Context.WindowService).JavaCast<IWindowManager>();
mLayout = new FrameLayout(this);
WindowManagerLayoutParams lp = new WindowManagerLayoutParams();
lp.Type = WindowManagerTypes.AccessibilityOverlay;
lp.Format = Format.Translucent;
lp.Flags |= WindowManagerFlags.NotFocusable;
lp.Width = WindowManagerLayoutParams.WrapContent;
lp.Height = WindowManagerLayoutParams.WrapContent;
lp.Gravity = GravityFlags.Top;
LayoutInflater inflater = (LayoutInflater)Application.Context.GetSystemService(Context.LayoutInflaterService);
inflater.Inflate(Resource.Layout.InputBar, mLayout);
wm.AddView(mLayout, lp);
}
}
布局文件(InputBar.xml):
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<Button
android:id="@+id/power"
android:text="Power"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<Button
android:id="@+id/volume_up"
android:text="Volume"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<Button
android:id="@+id/scroll"
android:text="Scroll"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<Button
android:id="@+id/swipe"
android:text="Swipe"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</LinearLayout>
元数据文件(config.xml):
<?xml version="1.0" encoding="utf-8" ?>
<accessibility-service xmlns:android="http://schemas.android.com/apk/res/android"
android:settingsActivity="true"
android:accessibilityFeedbackType="feedbackGeneric"
android:accessibilityFlags="flagDefault"
android:canPerformGestures="true"
android:canRetrieveWindowContent="true" />
但是,当我尝试在 wm.AddView(mLayout, lp);
处将叠加层添加到屏幕时出现错误,它给了我这个错误:Android.Views.WindowManagerBadTokenException Message=Unable to add window -- token null is not valid; is your activity running?
.
我知道在官方代码实验室中它告诉我像这样启动:
我怀疑这可能是我遇到的错误的来源,但我不在 android 工作室,我正在使用 Visual Studio 并且不知道该怎么做。
要重现我的错误,只需克隆我的 github 存储库,运行 它,然后在 运行ning 期间,转到 android 的设置 > 辅助功能模拟器并启用“输入服务”辅助功能服务。
Github 存储库:https://github.com/tatapuchi/XamarinAccessibilityService
要测试此功能,请标记确保 Settings.CanDrawOverlays
已启用。尝试在启动服务之前检测状态。
using Android.Provider;
...
if (!Settings.CanDrawOverlays(this))
{
StartActivityForResult(new Intent(Settings.ActionManageOverlayPermission, Android.Net.Uri.Parse("package:" + PackageName)), 0);
}
else
{
StartService(new Intent(this, typeof(DemoService)));
}
...
public override void OnActivityResult(int requestCode, [GeneratedEnum] Result resultCode, Intent data)
{
base.OnActivityResult(requestCode, resultCode, data);
if (requestCode == 0)
{
if (!Settings.CanDrawOverlays(this))
{
}
else
{
StartService(new Intent(this, typeof(DemoService)));
}
}
}
更新:
示例相关代码如下:
public class MainActivity : AppCompatActivity
{
public AccessibilityServiceBinder binder;
public AccessibilityServiceConnection accessibilityServiceConnection;
public bool isBound = false;
bool isBoundAC = false;
Intent ServiceIntent;
protected override void OnStart()
{
base.OnStart();
if (!isBoundAC)
{
accessibilityServiceConnection = new AccessibilityServiceConnection(this);
isBoundAC = BindService(ServiceIntent, accessibilityServiceConnection, Bind.AutoCreate);
if (isBoundAC)
{
Toast.MakeText(this, "AccessibilityService is Bound", ToastLength.Long);
}
}
}
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
Xamarin.Essentials.Platform.Init(this, savedInstanceState);
SetContentView(Resource.Layout.activity_main);
ServiceIntent = new Intent(this, typeof(TapService));
ServiceIntent.SetPackage("com.companyname.app19_3_1");
FindViewById<Button>(Resource.Id.btn).Click += async delegate
{
if (!Settings.CanDrawOverlays(this))
{
StartActivityForResult(new Intent(Settings.ActionManageOverlayPermission, Android.Net.Uri.Parse("package:" + PackageName)), 0);
}
};
}
}
public class AccessibilityServiceBinder : Binder
{
TapService service;
public AccessibilityServiceBinder(TapService service)
{
this.service = service;
}
public TapService GetAccessibilityService()
{
return service;
}
}
public class AccessibilityServiceConnection : Java.Lang.Object, IServiceConnection
{
MainActivity activity;
AccessibilityServiceBinder binder;
public AccessibilityServiceBinder Binder
{
get
{
return (AccessibilityServiceBinder)binder;
}
}
public AccessibilityServiceConnection(MainActivity activity)
{
this.activity = activity;
}
public void OnServiceConnected(ComponentName name, IBinder service)
{
var accessibilityServiceBinder = service as AccessibilityServiceBinder;
if (accessibilityServiceBinder != null)
{
activity.binder = accessibilityServiceBinder;
activity.isBound = true;
this.binder = accessibilityServiceBinder;
}
}
public void OnServiceDisconnected(ComponentName name)
{
activity.isBound = false;
}
}
[Service(Label = "Input Utility", Permission = Manifest.Permission.BindAccessibilityService, Enabled = true)]
[IntentFilter(new string[] { "android.accessibilityservice.AccessibilityService" })]
[MetaData("android.accessibilityservice", Resource = "@xml/config")]
public class TapService : AccessibilityService
{
FrameLayout mLayout;
...
protected override void OnServiceConnected()
{
base.OnServiceConnected();
IWindowManager wm = GetSystemService(Context.WindowService).JavaCast<IWindowManager>();
WindowManagerLayoutParams lp = new WindowManagerLayoutParams();
lp.Type = WindowManagerTypes.AccessibilityOverlay;
lp.Format = Format.Translucent;
lp.Flags |= WindowManagerFlags.NotFocusable;
lp.Width = WindowManagerLayoutParams.WrapContent;
lp.Height = WindowManagerLayoutParams.WrapContent;
lp.Gravity = GravityFlags.Top;
LayoutInflater inflater = (LayoutInflater)GetSystemService(Context.LayoutInflaterService);
View view = inflater.Inflate(Resource.Layout.layoutfloat, null);
wm.AddView(view, lp);
}
}
我正在使用 Xamarin 和 Visual Studio 创建无障碍服务,遵循此 Codelab (Java + Android SDK):https://codelabs.developers.google.com/codelabs/developing-android-a11y-service/#0
无障碍服务已启动,运行 可以在我的 android 设备的“设置”>“无障碍”中找到它。
服务:
[Service(Label = "Input Utility", Permission = Manifest.Permission.BindAccessibilityService)]
[IntentFilter(new string[] { "android.accessibilityservice.AccessibilityService" })]
[MetaData("android.accessibilityservice", Resource = "@xml/config")]
public class TapService : AccessibilityService
{
FrameLayout mLayout;
public override void OnAccessibilityEvent(AccessibilityEvent e)
{
}
public override void OnInterrupt()
{
}
public override bool OnUnbind(Intent intent)
{
return base.OnUnbind(intent);
}
protected override void OnServiceConnected()
{
base.OnServiceConnected();
IWindowManager wm = Application.Context.GetSystemService(Context.WindowService).JavaCast<IWindowManager>();
mLayout = new FrameLayout(this);
WindowManagerLayoutParams lp = new WindowManagerLayoutParams();
lp.Type = WindowManagerTypes.AccessibilityOverlay;
lp.Format = Format.Translucent;
lp.Flags |= WindowManagerFlags.NotFocusable;
lp.Width = WindowManagerLayoutParams.WrapContent;
lp.Height = WindowManagerLayoutParams.WrapContent;
lp.Gravity = GravityFlags.Top;
LayoutInflater inflater = (LayoutInflater)Application.Context.GetSystemService(Context.LayoutInflaterService);
inflater.Inflate(Resource.Layout.InputBar, mLayout);
wm.AddView(mLayout, lp);
}
}
布局文件(InputBar.xml):
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<Button
android:id="@+id/power"
android:text="Power"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<Button
android:id="@+id/volume_up"
android:text="Volume"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<Button
android:id="@+id/scroll"
android:text="Scroll"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<Button
android:id="@+id/swipe"
android:text="Swipe"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</LinearLayout>
元数据文件(config.xml):
<?xml version="1.0" encoding="utf-8" ?>
<accessibility-service xmlns:android="http://schemas.android.com/apk/res/android"
android:settingsActivity="true"
android:accessibilityFeedbackType="feedbackGeneric"
android:accessibilityFlags="flagDefault"
android:canPerformGestures="true"
android:canRetrieveWindowContent="true" />
但是,当我尝试在 wm.AddView(mLayout, lp);
处将叠加层添加到屏幕时出现错误,它给了我这个错误:Android.Views.WindowManagerBadTokenException Message=Unable to add window -- token null is not valid; is your activity running?
.
我知道在官方代码实验室中它告诉我像这样启动:
我怀疑这可能是我遇到的错误的来源,但我不在 android 工作室,我正在使用 Visual Studio 并且不知道该怎么做。
要重现我的错误,只需克隆我的 github 存储库,运行 它,然后在 运行ning 期间,转到 android 的设置 > 辅助功能模拟器并启用“输入服务”辅助功能服务。
Github 存储库:https://github.com/tatapuchi/XamarinAccessibilityService
要测试此功能,请标记确保 Settings.CanDrawOverlays
已启用。尝试在启动服务之前检测状态。
using Android.Provider;
...
if (!Settings.CanDrawOverlays(this))
{
StartActivityForResult(new Intent(Settings.ActionManageOverlayPermission, Android.Net.Uri.Parse("package:" + PackageName)), 0);
}
else
{
StartService(new Intent(this, typeof(DemoService)));
}
...
public override void OnActivityResult(int requestCode, [GeneratedEnum] Result resultCode, Intent data)
{
base.OnActivityResult(requestCode, resultCode, data);
if (requestCode == 0)
{
if (!Settings.CanDrawOverlays(this))
{
}
else
{
StartService(new Intent(this, typeof(DemoService)));
}
}
}
更新:
示例相关代码如下:
public class MainActivity : AppCompatActivity
{
public AccessibilityServiceBinder binder;
public AccessibilityServiceConnection accessibilityServiceConnection;
public bool isBound = false;
bool isBoundAC = false;
Intent ServiceIntent;
protected override void OnStart()
{
base.OnStart();
if (!isBoundAC)
{
accessibilityServiceConnection = new AccessibilityServiceConnection(this);
isBoundAC = BindService(ServiceIntent, accessibilityServiceConnection, Bind.AutoCreate);
if (isBoundAC)
{
Toast.MakeText(this, "AccessibilityService is Bound", ToastLength.Long);
}
}
}
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
Xamarin.Essentials.Platform.Init(this, savedInstanceState);
SetContentView(Resource.Layout.activity_main);
ServiceIntent = new Intent(this, typeof(TapService));
ServiceIntent.SetPackage("com.companyname.app19_3_1");
FindViewById<Button>(Resource.Id.btn).Click += async delegate
{
if (!Settings.CanDrawOverlays(this))
{
StartActivityForResult(new Intent(Settings.ActionManageOverlayPermission, Android.Net.Uri.Parse("package:" + PackageName)), 0);
}
};
}
}
public class AccessibilityServiceBinder : Binder
{
TapService service;
public AccessibilityServiceBinder(TapService service)
{
this.service = service;
}
public TapService GetAccessibilityService()
{
return service;
}
}
public class AccessibilityServiceConnection : Java.Lang.Object, IServiceConnection
{
MainActivity activity;
AccessibilityServiceBinder binder;
public AccessibilityServiceBinder Binder
{
get
{
return (AccessibilityServiceBinder)binder;
}
}
public AccessibilityServiceConnection(MainActivity activity)
{
this.activity = activity;
}
public void OnServiceConnected(ComponentName name, IBinder service)
{
var accessibilityServiceBinder = service as AccessibilityServiceBinder;
if (accessibilityServiceBinder != null)
{
activity.binder = accessibilityServiceBinder;
activity.isBound = true;
this.binder = accessibilityServiceBinder;
}
}
public void OnServiceDisconnected(ComponentName name)
{
activity.isBound = false;
}
}
[Service(Label = "Input Utility", Permission = Manifest.Permission.BindAccessibilityService, Enabled = true)]
[IntentFilter(new string[] { "android.accessibilityservice.AccessibilityService" })]
[MetaData("android.accessibilityservice", Resource = "@xml/config")]
public class TapService : AccessibilityService
{
FrameLayout mLayout;
...
protected override void OnServiceConnected()
{
base.OnServiceConnected();
IWindowManager wm = GetSystemService(Context.WindowService).JavaCast<IWindowManager>();
WindowManagerLayoutParams lp = new WindowManagerLayoutParams();
lp.Type = WindowManagerTypes.AccessibilityOverlay;
lp.Format = Format.Translucent;
lp.Flags |= WindowManagerFlags.NotFocusable;
lp.Width = WindowManagerLayoutParams.WrapContent;
lp.Height = WindowManagerLayoutParams.WrapContent;
lp.Gravity = GravityFlags.Top;
LayoutInflater inflater = (LayoutInflater)GetSystemService(Context.LayoutInflaterService);
View view = inflater.Inflate(Resource.Layout.layoutfloat, null);
wm.AddView(view, lp);
}
}