Issue
I'm working on a Xamarin Forms app that uses a Bluetooth shutter clicker to take photos. Currently, the Bluetooth shutter activates the volume up/down buttons when being clicked. I am trying to intercept the volume buttons so that I can instead open the device camera when the clicker is clicked.
I am trying to get the Android version working. I can successfully intercept the volume buttons in my Android code in my MainActivity.cs file. I think I have to use a dependency service so that my CameraButton_Clicked event is triggered by the volume buttons, but I am lost on how to properly go about doing this. Any help would be hugely appreciated.
MainActivity.CS:
//override the volume up/down buttons for bluetooth shutter clicker
public override bool OnKeyUp(Keycode keyCode, KeyEvent e)
{
if (keyCode == Keycode.VolumeDown)
{
return true;
}
if (keyCode == Keycode.VolumeUp)
{
return true;
}
return base.OnKeyUp(keyCode, e);
}
public override bool OnKeyDown(Keycode keyCode, KeyEvent e)
{
if (keyCode == Keycode.VolumeDown)
{
return true;
}
if (keyCode == Keycode.VolumeUp)
{
return true;
}
return base.OnKeyDown(keyCode, e);
}
Interface:
namespace MyApp
{
public interface IBluetoothClicker
{
object GetVolumeOverride();
}
}
BluetoothClicker_Droid.cs:
[assembly: Xamarin.Forms.Dependency (typeof (BluetoothClicker_Droid))]
namespace MyApp.Droid
{
public class BluetoothClicker_Droid: IBluetoothClicker
{
public BluetoothClicker_Droid ()
{
}
public object GetVolumeOverride()
{
//CameraButton_Clicked = true;
return true;
}
}
}
CameraPage.xaml.cs:
public CameraPage()
{
InitializeComponent();
CameraImage.Source = "CameraImage.png";
TakePhotoButton.Clicked += CameraButton_Clicked; //opens camera
Func<object> func = () =>
{
var obj = DependencyService.Get<IBluetoothClicker>().GetVolumeOverride();
//obj += CameraButton_Clicked;
return obj;
};
}
Solution
If you just want to achieve that in android. you could open the camera directly like following GIF.
You can take a photo in android, Then use message center to upload your image in PCL like followcode.
MainPage.xaml.cs
public partial class MainPage : ContentPage
{
public MainPage()
{
InitializeComponent();
CameraImage.Source = "CameraImage.png";
MessagingCenter.Subscribe<App, string>(App.Current, "OpenPage", (snd, arg) =>
{
Device.BeginInvokeOnMainThread(() => {
CameraImage.Source = arg;
});
});
}
}
MainActivity.cs
public static class App_test
{
public static File _file;
public static File _dir;
public static Bitmap bitmap;
}
[Activity(Label = "InterceptButton", Icon = "@mipmap/icon", Theme = "@style/MainTheme", MainLauncher = true, ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation)]
public class MainActivity : global::Xamarin.Forms.Platform.Android.FormsAppCompatActivity
{
protected override void OnCreate(Bundle savedInstanceState)
{
StrictMode.VmPolicy.Builder builder = new StrictMode.VmPolicy.Builder();
StrictMode.SetVmPolicy(builder.Build());
TabLayoutResource = Resource.Layout.Tabbar;
ToolbarResource = Resource.Layout.Toolbar;
base.OnCreate(savedInstanceState);
Xamarin.Essentials.Platform.Init(this, savedInstanceState);
global::Xamarin.Forms.Forms.Init(this, savedInstanceState);
LoadApplication(new App());
if (IsThereAnAppToTakePictures())
{
CreateDirectoryForPictures();
}
}
public override void OnRequestPermissionsResult(int requestCode, string[] permissions, [GeneratedEnum] Android.Content.PM.Permission[] grantResults)
{
Xamarin.Essentials.Platform.OnRequestPermissionsResult(requestCode, permissions, grantResults);
base.OnRequestPermissionsResult(requestCode, permissions, grantResults);
}
public override bool OnKeyUp([GeneratedEnum] Keycode keyCode, KeyEvent e)
{
if (keyCode == Keycode.VolumeDown)
{
Toast.MakeText(this, "OnKeyUp-VolumeDown", ToastLength.Short).Show();
return true;
}
if (keyCode == Keycode.VolumeUp)
{
// Toast.MakeText(this, "OnKeyUp-VolumeUp", ToastLength.Short).Show();
return true;
}
return base.OnKeyUp(keyCode, e);
}
public override bool OnKeyDown([GeneratedEnum] Keycode keyCode, KeyEvent e)
{
if (keyCode == Keycode.VolumeDown)
{
Toast.MakeText(this, "OnKeyDown-VolumeDown", ToastLength.Short).Show();
return true;
}
if (keyCode == Keycode.VolumeUp)
{
Intent intent = new Intent(MediaStore.ActionImageCapture);
App_test._file = new File(App_test._dir, String.Format("myPhoto_{0}.jpg", Guid.NewGuid()));
intent.PutExtra(MediaStore.ExtraOutput, Uri.FromFile(App_test._file));
StartActivityForResult(intent, 0);
Toast.MakeText(this, "OnKeyDown-VolumeUp", ToastLength.Short).Show();
return true;
}
return base.OnKeyDown(keyCode, e);
}
protected override void OnActivityResult(int requestCode, Result resultCode, Intent data)
{
base.OnActivityResult(requestCode, resultCode, data);
Intent mediaScanIntent = new Intent(Intent.ActionMediaScannerScanFile);
Uri contentUri = Uri.FromFile(App_test._file);
mediaScanIntent.SetData(contentUri);
SendBroadcast(mediaScanIntent);
App_test.bitmap = App_test._file.Path.LoadAndResizeBitmap(100, 100);
string path= App_test._file.Path;
if (App_test.bitmap != null)
{
MessagingCenter.Send<App, string>(App.Current as App, "OpenPage", path);
App_test.bitmap = null;
}
GC.Collect();
}
private void CreateDirectoryForPictures()
{
App_test._dir = new File(
Environment.GetExternalStoragePublicDirectory(
Environment.DirectoryPictures), "CameraAppDemo");
if (!App_test._dir.Exists())
{
App_test._dir.Mkdirs();
}
}
private bool IsThereAnAppToTakePictures()
{
Intent intent = new Intent(MediaStore.ActionImageCapture);
IList<ResolveInfo> availableActivities =
PackageManager.QueryIntentActivities(intent, PackageInfoFlags.MatchDefaultOnly);
return availableActivities != null && availableActivities.Count > 0;
}
}
So I do not know why you want to use DependencyService
.Maybe you have better ways to achieve that.
There is my demo. I used VS 2019, it will make some difference If you used VS 2017.
https://github.com/851265601/InterceptButton
Answered By - Leon Lu - MSFT
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.