Issue
I am creating an accessibility service using Xamarin and Visual Studio, following this Codelab (Java + Android SDK): https://codelabs.developers.google.com/codelabs/developing-android-a11y-service/#0
The accessibility service is up and running with it being found in Settings > Accessibility in my android device.
Service:
[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);
}
}
Layout File(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>
Metadata file (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" />
However I am getting an error when I try to add the overlay to the screen at wm.AddView(mLayout, lp);, it gives me this error: Android.Views.WindowManagerBadTokenException Message=Unable to add window -- token null is not valid; is your activity running?.
I understand that in the official codelab it tells me to launch like so:

I suspect this may be the source of the error I'm getting, however I am not on android studio, I am using Visual Studio and do not know what to do with this.
To reproduce my error simply clone my github repository, run it, then while it is running, go to the Settings > Accessibility of your android emulator and enable the "Input Service" accessibility service.
Github Repository: https://github.com/tatapuchi/XamarinAccessibilityService
Solution
To test this function, please mark sure the Settings.CanDrawOverlays has been enabled. Try detect the status before starting the service.
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)));
}
}
}
Update:
Here is the related code about the sample:
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);
}
}
Answered By - Jarvan Zhang - MSFT
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.