Capture android TV remote keycode - keyevent

My android app has a function to detect all the keycodes for TV remote.
I tried onKeyDown(up) API to detect when the user press the TV remote and override dispatchKeyEvent method too. It works except some keys : mute, volume, home, back. how can I detect those keys?
Thanks,

The system has the privilege to control those keys, so I have to find some source code to use.
I final resolved this problem. In general, AOSP dispose a led service (led controller):
public LedService() {
}
public IBinder onBind(Intent intent) {
this.handlePowerStateChanged(0);
return new LedService.LedServiceWrapper();
}
public void handlePowerStateChanged(int state) {
if (DEBUG) {
Log.d(TAG, "handlePowerStateChanged: " + state);
}
}
public void handleKeyEvent(KeyEvent event) {
if (DEBUG) {
Log.d(TAG, "handleKeyEvent: " + event);
}
}
This class use HAL to go down the level and communicate directly with system. I extend this class in my own class and use handleKeyEvent method.
Cheers,

Check the KeyEvent constants, and by the help of the following SO references.
Detect home button press in android
Check if back key was pressed in android?
Android: How to get app to remember if mute button has been pressed or not
Android - Volume Buttons used in my application

Related

Xamarin Android RequestPermissions( ) doesn't work 2nd time. No permissions popup Dialog 2nd time

I am writing a Xamarin (android flavor) app, OS 12, and am trying to call ActivityCompat.RequestPermissions. Maybe I'm expecting the wrong behavior, since I'm not familiar with this stuff. I expect no matter how many times I run the app, that calling ActivityCompat.RequestPermissions( xxx, yyy, 1 ) will popup a system OS dialog box and ask the user to permit or deny the permissions I specify...
In my MainActivity for my Xamarin Forms (android) app, I correctly init Xamarin Essentials...
I override OnRequestPermissionsResult( )....
Now, in my one LoginViewModel, I call back into MainActivity (via a callback) and inside THAT callback, in MainActivity, it calls
public void Foo()
{
foreach (string s in m_szNeededAppPermissions)
{
bool b = ActivityCompat.ShouldShowRequestPermissionRationale(this, s);
System.Diagnostics.Debug.WriteLine("should show request for " + s + ", = " + b);
}
ActivityCompat.RequestPermissions(this, m_szNeededAppPermissions.ToArray(), 1);
}
Not that big of a deal, right? First time I run the app, the OS dialog for allowing permissions work GREAT. Now if I press "Deny" in those permissions dialogs, I get called back with OnRequestPermissionsResult( ) and the grantResults are -1. Super, that's what I'd expect.
Now, if I stop the app debugging and run it AGAIN, the 2nd time it calls Foo( ) which calls ActivityCompat.RequestPermissions( ), I get a callback immediately with OnRequestPermissionsResult( ) with denied grantResults. No OS dialogs. If I go in and delete the app and re-start debugging, I DO get the OS permission dialogs again.
I think it's because when I say "No" to the 1st-run OS permissions dialogs, it's taking that answer as "never ask again". I think somehow the OS itself is remembering not to show the OS dialogs a 2nd time, even though i'm ASKING it to! How weird!
I think my expectations must be off, or I'm missing 1 key step. Can anybody explain why?
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);
// OS dialog ran and told us which permissions user accepted vs which ones they denied.
// We look at them and then call back with whether they all succeeded or not.
bool bGotAllPermissions = true;
foreach( Permission p in grantResults )
{
if( p != Permission.Granted )
{
bGotAllPermissions = false;
break;
}
}
// ps.OnRequestPermissionsResult(bGotAllPermissions);
}
here is the main activity:
public class MainActivity : global::Xamarin.Forms.Platform.Android.FormsAppCompatActivity, ICallbackApp
{
PermissionsService ps;
string[] m_szNeededAppPermissions = { Manifest.Permission.AccessFineLocation, Manifest.Permission.BluetoothAdmin };
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
Xamarin.Essentials.Platform.Init(this, savedInstanceState);
global::Xamarin.Forms.Forms.Init(this, savedInstanceState);
DependencyService.RegisterSingleton<ICallbackApp>(this);
ps = new PermissionsService(this, m_szNeededAppPermissions);
LoadApplication(new App());
}
and in the view model:
public LoginViewModel()
{
LoginCommand = new Command(OnLoginClicked);
// m_pCrossPlatUtils = DependencyService.Get<ICrossPlatUtils>();
// RefreshPermissions();
Foo();
}
public void Foo()
{
ICallbackApp p = DependencyService.Get<ICallbackApp>();
p.Foo();
}
The answer these days is different than it used to be. Both iOS and Android are getting tighter about "bugging users for permissions". If you open the system OS permissions dialog to ask the user for permission, if they Deny them, then on successive runs of the app, or future usages of RequestPermissions( ), it WILL NOT SHOW the OS permissions dialog for those permissions that were denied previously! Yeah. That.
The only ways around this, if your app needs those permissions to run are:
Ask the user to reinstall the app
Bring up the app's settings pages and ask them to "fix it themselves", and then verify it is fixed when the user returns to the temporarily backgrounded app (backgrounded in order to show the App's settings page)
I think this is all true, I got it from a pretty reliable Xamarin source # MSFT....
Yes,in xamarin, we recommend you use Xamarin.Essentials: Permissions just as json said,which provides the ability to check and request runtime permissions.
This API uses runtime permissions on Android. Please ensure that Xamarin.Essentials is fully initialized and permission handling is setup in your app.
In the Android project's MainLauncher or any Activity that is launched Xamarin.Essentials must be initialized in the OnCreate method:
protected override void OnCreate(Bundle savedInstanceState)
{
//...
base.OnCreate(savedInstanceState);
Xamarin.Essentials.Platform.Init(this, savedInstanceState); // add this line to your code, it may also be called: bundle
//...
}
To handle runtime permissions on Android, Xamarin.Essentials must receive any OnRequestPermissionsResult. Add the following code to all Activity classes:
public override void OnRequestPermissionsResult(int requestCode, string[] permissions, Android.Content.PM.Permission[] grantResults)
{
Xamarin.Essentials.Platform.OnRequestPermissionsResult(requestCode, permissions, grantResults);
base.OnRequestPermissionsResult(requestCode, permissions, grantResults);
}
For more,, you can check document:https://learn.microsoft.com/en-us/xamarin/essentials/permissions?tabs=android .

How to change state of Bluetooth on iOS is PowerOn on Xamarin Forms?

On iOS, I only can check state of Bluetooth. I'm find the solutions on network and use it.
public class CallBluetoothIphoneService : ICallBlueTooth
{
public void LaunchBluetoothOnPhone()
{
try
{
// Is bluetooth enabled?
var bluetoothManager = new CBCentralManager();
if (bluetoothManager.State == CBCentralManagerState.PoweredOff|| bluetoothManager.State == CBCentralManagerState.Unknown)
// Does not go directly to bluetooth on every OS version though, but opens the Settings on most
UIApplication.SharedApplication.OpenUrl(new NSUrl("App-Prefs:root=Bluetooth"));
}
catch (Exception ex)
{
Console.WriteLine(ex);
throw;
}
}
}
But when I try turn off Bluetooth and test code, state of bluetooth is "Unknown".
Then I run code, device open settings, toggle button has color green (turn on bluetooth), but when I check state of Bluetooth in code, State of Bluetooth is "Unknown", is not "Power on".
I'm using Xamarin 3.3 and test on device iOS version 12.0.
I am not sure exactly what you want to do, but if your intent is to open the Bluetooth settings page, this:
UIApplication.SharedApplication.OpenUrl(new NSUrl("App-Prefs:root=Bluetooth"));
won't work. Apple has at some points allowed this (iOS 8 IIRC) and at other points it has disallowed this (most versions of iOS). See this long SO thread about this issue: How to open Settings programmatically like in Facebook app?
Regardless, there is no need. When iOS detects that your app has created a CBCentralManager type with delegate, iOS will display an alert to the user that allows them to go to the bluetooth settings to enable bluetooth by tapping the "Settings" button in the alert.
As far as always getting state as "Unknown", you need to check the state in the delegate for the CBCentralManager. You cannot use the parameterless CBCentralManager constructor new CBCentralManager();. Check the apple docs: https://developer.apple.com/documentation/corebluetooth/cbcentralmanager?language=objc and note that there are only two listed init methods, one that takes delegate and queue parameters, and one that takes delegate, queue, and options parameters, although no one complains if you use the parameterless constructor... but you will never get the correct state if you use it. See: https://stackoverflow.com/a/36824770/2913599
So try this:
public class CallBluetoothIphoneService : ICallBluetooth
{
public void LaunchBluetoothOnPhone()
{
try
{
// Is bluetooth enabled?
var bluetoothManager = new CBCentralManager(new MySimpleCBCentralManagerDelegate(), DispatchQueue.CurrentQueue);
// This will always show state "Unknown". You need to check it in the delegate's UpdatedState method
Console.WriteLine($"State: {bluetoothManager.State.ToString()}");
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
}
}
public class MySimpleCBCentralManagerDelegate : CBCentralManagerDelegate
{
override public void UpdatedState(CBCentralManager mgr)
{
// You can check the state in this delegate method
Console.WriteLine($"UpdatedState: {mgr.State.ToString()}");
if (mgr.State == CBCentralManagerState.PoweredOn)
{
//Passing in null scans for all peripherals. Peripherals can be targeted by using CBUIIDs
CBUUID[] cbuuids = null;
mgr.ScanForPeripherals(cbuuids); //Initiates async calls of DiscoveredPeripheral
//Timeout after 30 seconds
var timer = new Timer(30 * 1000);
timer.Elapsed += (sender, e) => mgr.StopScan();
}
else
{
//Invalid state -- Bluetooth powered down, unavailable, etc.
System.Console.WriteLine("Bluetooth is not available");
}
}
public override void DiscoveredPeripheral(CBCentralManager central, CBPeripheral peripheral, NSDictionary advertisementData, NSNumber RSSI)
{
Console.WriteLine("Discovered {0}, data {1}, RSSI {2}", peripheral.Name, advertisementData, RSSI);
}
}
Bottom line: always create a CBCentralManager object with one of the following constructors:
CBCentralManager(ICBCentralManagerDelegate, DispatchQueue)
CBCentralManager(ICBCentralManagerDelegate, DispatchQueue, CBCentralInitOptions)

Start specific view of Gluon App from a notification

I set up an alarm to show a corresponding Notification. The PendingIntent of the Notification is used to start the Gluon App main class. To show a View other than the homeView, I call switchView(otherView) in the postInit method. OtherView is shown, but without AppBar. While it's possible to make the AppBar appear, I wonder if this is the right approach.
#Override
public void postInit(Scene scene) {
// additional setUp logic
boolean showReadingView = (boolean) PlatformProvider.getPlatform().getLaunchIntentExtra("showReadingView", false);
if (showReadingView) {
switchView(READING_VIEW);
}
}
When triggering anything related to the JavaFX thread from another thread, we have to use Platform.runLater().
Yours is a clear case of this situation: the Android thread is calling some pending intent, and as a result, the app is started again.
This should be done:
#Override
public void postInit(Scene scene) {
// additional setUp logic
boolean showReadingView = (boolean) PlatformProvider.getPlatform().getLaunchIntentExtra("showReadingView", false);
if (showReadingView) {
Platform.runLater(() -> switchView(READING_VIEW));
}
}

Delay in Android Wear putDataItem() and invoking of onDataChanged()

I want to use the action button "Open" on a notification on my Android Wear application, to open a Dialog with some task data on my handheld. To do this, I put my message in a PutDataMapRequest and use the following method in my Wearable code:
PutDataMapRequest dataMap = PutDataMapRequest.create("/task/" + "1");
dataMap.getDataMap().putString(DataMapKeys.TASK_MESSAGE, message);
....
dataMap.getDataMap().putLong("timestamp", System.currentTimeMillis());
PutDataRequest putDataRequest = dataMap.asPutDataRequest();
Wearable.DataApi.putDataItem(googleApiClient, putDataRequest).setResultCallback(new ResultCallback<DataApi.DataItemResult>() {
#Override
public void onResult(DataApi.DataItemResult dataItemResult) {
Log.d(TAG, "Sending task data: " + dataItemResult.getStatus().isSuccess());
}
});
And then, to catch it in my WearableListenerService on my handheld/mobile device:
#Override
public void onDataChanged(DataEventBuffer dataEvents) {
Log.d(TAG, "Received task data, now opening dialog..");
}
However, there is a significant delay (about 10 seconds) between the call to onResult() in the putDataItem() method in my Wear app, and the invoking of the onDataChanged() method in my mobile app. This means that when I press the "Open" Action button on the notification on my watch, the dialog opens about 10 seconds later on my phone. I would like this to be instant, if possible.
Is this possible, or am I doing something wrong here in my code?
Best,
Switch to using MessageApi. It is intended for situations like this: it doesn't have a guarantee of delivery (if the devices are not connected at the moment), but is fast. And clicking a button is exactly the situation where it should be used (because user can repeat it).

how to disable location services in my WP7 app

I'm making a windows phone app which displays where the closest campus shuttles are (among other things). Windows Phone requires apps to allow the users to turn off location services within the app.
So, I added a toggle for it on a settings page, but it doesn't seem to do anything.
Here's the viewmodel where I declared the geocoordinatewatcher.
public MainViewModel()
{
geoWatcher = new GeoCoordinateWatcher();
if (geoWatcher.TryStart(false, TimeSpan.FromSeconds(30) )==false )
{ MessageBox.Show("The location services are disabled for this app. We can't detect the nearby stops. To turn location services back on, go to the settings page.", "Warning", MessageBoxButton.OK); }
}
private GeoCoordinateWatcher geoWatcher;
public GeoCoordinateWatcher GeoWatcher
{
get
{
return geoWatcher;
}
set
{
if (geoWatcher != value)
{
geoWatcher = value;
NotifyPropertyChanged("GeoWatcher");
}
if(geoWatcher.Status== GeoPositionStatus.Disabled)
{
geoWatcher.Stop();
}
}
}
and here's the bulk of the settings page
public SettingsPage()
{
InitializeComponent();
if (App.ViewModel.GeoWatcher.Status == GeoPositionStatus.Ready)
{
locToggle.IsChecked = true;
locToggle.Content = "On";
}
else
{
locToggle.IsChecked = false;
locToggle.Content = "Off";
}
}
private void toggleChecked(object sender, RoutedEventArgs e)
{
locToggle.Content = "On";
App.ViewModel.GeoWatcher.Start();
MessageBox.Show("this is the status " + App.ViewModel.GeoWatcher.Status.ToString(), "Info", MessageBoxButton.OK); //for debugging
}
private void toggleUnchecked(object sender, RoutedEventArgs e)
{
locToggle.Content = "Off";
App.ViewModel.GeoWatcher.Stop();
MessageBox.Show("this is the status " + App.ViewModel.GeoWatcher.Status.ToString(), "Info", MessageBoxButton.OK); //for debugging
}
When i turn the toggle off and click away from the Settings page, and go back to it, the toggle is re-enabled again.
I tried putting in a message box on the functions to debug but the status always says "Ready" and my app still uses the location services, even when I turn the toggle to "off".
Is there something I should be adding to the code so that the toggle will properly make my app stop using location services across my app if it's disabled on the settings page? Or should I be checking something else besides GeoPositionStatus? I couldn't figure out a way to make my app actually change the location services permissions or PositionStatus.
I looked at this page here, but am still confused since I followed the example at the bottom of the page, to no avail. I searched StackOverflow but I couldn't seem to find a similar question with WP. I also posted this on the AppHub forums though.
Thanks!
In your MainViewModel you need to check if they have allowed location services before you use the geocoordinatewatcher.
if(settings.LocationAllowed)
{all your code for using location}
You should probably take into account a few factors/points, most of which, you have. Anyway, you might find these helpful.
Your application settings toggle should only show when the location service is switched on on the device
GeoPositionStatus is just an Enum which contains the types of statuses.
StatusChanged is the event which is to be handled to check for changes in the device settings. See this.
You cannot change the device settings from the application.
Add event handlers before you call start on the watcher.

Resources