c# - 如何拦截 Android 设备音量增大/减小按钮以在 Xamarin Forms 应用程序中打开相机?
问题描述
我正在开发一个使用蓝牙快门点击器拍照的 Xamarin Forms 应用程序。目前,蓝牙快门在被点击时会激活音量增大/减小按钮。我正在尝试拦截音量按钮,以便在单击答题器时打开设备摄像头。
我正在尝试使 Android 版本正常工作。我可以在我的 MainActivity.cs 文件中成功拦截我的 Android 代码中的音量按钮。我想我必须使用依赖服务,以便我的 CameraButton_Clicked 事件由音量按钮触发,但我不知道如何正确执行此操作。任何帮助将不胜感激。
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);
}
界面:
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;
};
}
解决方案
如果你只是想在android中实现这一点。你可以像下面的GIF一样直接打开相机。
您可以在 android 中拍照,然后使用消息中心将您的图像上传到 PCL 中,如跟随代码。
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;
}
}
所以我不知道你为什么要使用DependencyService
. 也许你有更好的方法来实现这一点。
有我的演示。我使用的是 VS 2019,如果你使用的是 VS 2017,它会有所不同。
推荐阅读
- html - 使用固定的列数,在上一列中已经添加了固定数量的项目之后,下一个项目应该转到下一列
- ios - SwiftUI - 表单中的 NavigationLink 单元格在详细信息弹出后保持突出显示
- firebase - FIreStore 规则 - 带有 2 个参数的集合的安全规则
- rest - x-www-form-url-encoded POST 请求不被接受
- laravel - Laravel 图表 - 在图表中显示值
- asp.net-core - 如何在 identityserver4 中没有用户名和密码的情况下从令牌端点获取令牌?
- python - 修改 A* 算法以使其处理不同的单元格值
- jenkins - 如何在 Jenkinsfile 中调用函数
- javascript - 如何在 javascript 的数组中获取 [] 而不是 {}
- deep-learning - RNN 中的梯度累积