Turning Bluetooth Tethering On in Xamarin.Android - xamarin

I'm currently trying to add some Bluetooth functionality to my app. I want to be able to change the Bluetooth Tethering on or off, as well as check its status.
I found the Java code on StackOverflow: How to check Bluetooth tethering status programmatically in Android
I have translated it into C#, but I don't seem to be able to get any result.
Regardless of the tethering setting, it always shows the toast with "Tethering:false", and the setBluetoothTethering doesn't change anything.
Any idea what I'm missing?
Here's my code:
[...]
try
{
Class classBluetoothPan = Class.ForName("android.bluetooth.BluetoothPan");
Method mBTPanConnect = classBluetoothPan.GetDeclaredMethod("connect", Class.FromType(typeof(BluetoothDevice)));
Constructor BTPanCtor = classBluetoothPan.GetDeclaredConstructor(Class.FromType(typeof(Context)), Class.FromType(typeof(IBluetoothProfileServiceListener)));
BTPanCtor.Accessible = true;
Java.Lang.Object BTSrvInstance = BTPanCtor.NewInstance(Activity, new BTPanServiceListener(Activity));
Method isTetheringOnMethod = classBluetoothPan.GetDeclaredMethod("isTetheringOn", null);
var isTetheringOn = isTetheringOnMethod.Invoke(BTSrvInstance);
Toast.MakeText(Activity, "Tethering:" + isTetheringOn, ToastLength.Short).Show();
Method setBluetoothTetheringMethod = classBluetoothPan.GetDeclaredMethod("setBluetoothTethering", new Class[1] { Class.FromType(typeof(bool)) });
setBluetoothTetheringMethod.Invoke(BTSrvInstance, true);
// tether = !tether;
}
catch (ClassNotFoundException e)
{
e.PrintStackTrace();
}
catch (Java.Lang.Exception e)
{
e.PrintStackTrace();
}
[...]
public class BTPanServiceListener : Java.Lang.Object, IBluetoothProfileServiceListener
{
private Activity _activity;
public BTPanServiceListener(Activity activity)
{
_activity = activity;
}
public void OnServiceConnected([GeneratedEnum] ProfileType profile, IBluetoothProfile proxy)
{
// throw new NotImplementedException();
}
public void OnServiceDisconnected([GeneratedEnum] ProfileType profile)
{
// throw new NotImplementedException();
}
}

I figured out how to enable Bluetooth tethering via setBluetoothTethering.
I wrote an entire blog about this
You can find the final code here
I assume that isTetheringOn works in the same way

Related

How to prevent sharing files from "On My iPhone" folder

I have a xamarin forms app that can download files to "on my iphone" folder. But when I download a file on phone, I can go there and I can share it with another app.
But I want to prevent this. When I download a file from my app, I want the file not to be uploaded to another device from "on my iphone".
How to prevent this? Probably I can prevent this with mdm, but how?
Is there a way to prevent it with mdm managed app configuration. Some of my customers said that we can prevent this with the plist file in mdm. But I have very little information about mdm. How to do it with mdm?
I need a solution for ios and android. But especially for ios.
Thank you in advance.
Thank you for reply Jack.
I looked your sending thread and I tried it. But it didn't work for me.
I created MyUINavigationItem that is inherited from UINavigationItem. And I override SetRightBarButtonItem null. After I override UINavigationItem on PdfPreviewController that is inherited from QLPreviewController. And I set NavigationItem as MyUINavigationItem object. But it doesn't work for me. My codes is like these:
public class DocumentView : IDocumentView
{
void IDocumentView.DocumentView(string file, string title)
{
PdfPreviewController previewController = new PdfPreviewController();
if (File.Exists(file))
{
previewController.NavigationItem.SetRightBarButtonItem(null, false); //I tried this line as both comment and not comment but it didn't work
previewController.NavigationItem.SetRightBarButtonItems(null, false); //I tried this line as both comment and not comment but it didn't work
previewController.DataSource = new PDFPreviewControllerDataSource(NSUrl.FromFilename(file), title);
UIApplication.SharedApplication.KeyWindow.RootViewController.PresentViewController(previewController, true, null);
}
}
}
public class PdfPreviewController : QLPreviewController
{
MyUINavigationItem item = new MyUINavigationItem();
public override UINavigationItem NavigationItem => item;
}
public class MyUINavigationItem : UINavigationItem
{
public MyUINavigationItem()
{
}
public override void SetRightBarButtonItem(UIBarButtonItem item, bool animated)
{
//base.SetRightBarButtonItem(item, animated); //I tried this line as comment but it didn't work or
//base.SetRightBarButtonItem(null, animated); //I tried this line but it didn't work
}
public override void SetRightBarButtonItems(UIBarButtonItem[] items, bool animated)
{
//base.SetRightBarButtonItems(items, animated); //I tried this line as comment but it didn't work or
//base.SetRightBarButtonItems(null, animated); //I tried this line but it throwed exception
//base.SetRightBarButtonItems(new UIBarButtonItem[0], animated); //I tried this line but it didn't work
}
}
But after your suggestion I looked for enable or hide share button. And I could access child view controller of UINavigationController and I set RightBarButtonItem enable value false.
public class PdfPreviewController : QLPreviewController
{
public override void ViewDidAppear(bool animated)
{
try
{
ActionMenuControl();
}
catch (Exception ex)
{
}
}
public override void ViewDidLayoutSubviews()
{
try
{
ActionMenuControl();
}
catch (Exception ex)
{
}
}
public void ActionMenuControl()
{
try
{
if (this.ChildViewControllers.Length != 0)
{
var navigationController = this.ChildViewControllers.First() as UINavigationController;
if (navigationController.View.Subviews.Length != 0)
{
var layoutContainerView = navigationController.View.Subviews.FirstOrDefault(x => x is UINavigationBar) as UINavigationBar;
if (layoutContainerView != null)
{
if (layoutContainerView.Items.Length != 0)
{
var item = layoutContainerView.Items[0];
if (item.RightBarButtonItems.Length != 0)
item.RightBarButtonItem.Enabled = false;
}
}
}
var toolbar = navigationController.Toolbar;
if (toolbar != null)
{
if(toolbar.Items.Length != 0)
{
toolbar.Items[0].Enabled = false;
}
}
}
}
catch (Exception ex)
{
}
}
}
It works for right bar. But if opens mp3 files, share button appear on toolbar (on bottom) And I didn't access it. How can I do it for mp3 files? How to access toolbar? (Actually it doesn't work when opens and not move it. But if I open it and move it, it works (because it enters ViewDidLayoutSubviews events))
Sorry for long reply. But I wanted to tell about what I did. Because maybe I did missed something.

How to implement Play Install Referrer API in Android?

I want to implement Play Install Referrer API and I found document and I read that but I have have some confusion. First I have implemented all code provided by google. But I want to know which type of url I need to create so that user can click on link and go to play store and install my app and then I get the referral detail..
I use this code:
InstallReferrerClient mReferrerClient;
mReferrerClient = newBuilder(this).build();
mReferrerClient.startConnection(this);
#Override
public void onInstallReferrerSetupFinished ( int responseCode){
switch (responseCode) {
case InstallReferrerClient.InstallReferrerResponse.OK:
// Connection established
/* ReferrerDetails response = null;
try {
response = mReferrerClient.getInstallReferrer();
response.getInstallReferrer();
response.getReferrerClickTimestampSeconds();
response.getInstallBeginTimestampSeconds();
} catch (RemoteException e) {
e.printStackTrace();
}*/
break;
case InstallReferrerClient.InstallReferrerResponse.FEATURE_NOT_SUPPORTED:
// API not available on the current Play Store app
break;
case InstallReferrerClient.InstallReferrerResponse.SERVICE_UNAVAILABLE:
// Connection could not be established
break;
}
}
#Override
public void onInstallReferrerServiceDisconnected () {
}
But which type of link I create so user go to play store and after install play store referral api give me data..
Sample url - "https://play.google.com/store/apps/details?id=com.dummy.app&referrer=referralCode%3D311566%26source%3DFacebook+App"
When using the Google Play Referrer API -
InstallReferrerClient mReferrerClient;
mReferrerClient = newBuilder(this).build();
mReferrerClient.startConnection(this);
#Override
public void onInstallReferrerSetupFinished ( int responseCode){
switch (responseCode) {
case InstallReferrerClient.InstallReferrerResponse.OK:
// Connection established
/* ReferrerDetails response = null;
try {
response = mReferrerClient.getInstallReferrer();
response.getInstallReferrer();
response.getReferrerClickTimestampSeconds();
response.getInstallBeginTimestampSeconds();
} catch (RemoteException e) {
e.printStackTrace();
}*/
// End the connection once you get the data
referrerClient.endConnection();
break;
case InstallReferrerClient.InstallReferrerResponse.FEATURE_NOT_SUPPORTED:
// API not available on the current Play Store app
break;
case InstallReferrerClient.InstallReferrerResponse.SERVICE_UNAVAILABLE:
// Connection could not be established
break;
}
}
#Override
public void onInstallReferrerServiceDisconnected () {
}
getInstallReferrer()
will return String 'referralCode=311566&source=Facebook App'
play install referral library i wants to describe this in simple wording, being a developer you wants to know about these elements how much time you app bundle take to install on the user devices from play store, and referral url , referral click time and many others elements , google make it easy for you know you have to use play install referral library for this purpose.
add this dependency
implementation 'com.android.installreferrer:installreferrer:1.1'
you can follow the guidelines from here:
play installer referral guidelines
declare this variable in any java activity
InstallReferrerClient referrerClient;
in on create method use this code below :
referrerClient = InstallReferrerClient.newBuilder(this).build();
referrerClient.startConnection(new InstallReferrerStateListener() {
#Override
public void onInstallReferrerSetupFinished(int responseCode) {
switch (responseCode) {
case InstallReferrerClient.InstallReferrerResponse.OK:
// Connection established.
break;
case InstallReferrerClient.InstallReferrerResponse.FEATURE_NOT_SUPPORTED:
// API not available on the current Play Store app.
break;
case InstallReferrerClient.InstallReferrerResponse.SERVICE_UNAVAILABLE:
// Connection couldn't be established.
break;
}
}
#Override
public void onInstallReferrerServiceDisconnected() {
// Try to restart the connection on the next request to
// Google Play by calling the startConnection() method.
}
});
inside onInstallReferrerSetupFinished stabled you can get these data easily,you code will be after that like this
ReferrerDetails response = null;
try {
response = referrerClient.getInstallReferrer();
} catch (RemoteException e) {
e.printStackTrace();
}
String referrerUrl = response.getInstallReferrer();
long referrerClickTime = response.getReferrerClickTimestampSeconds();
long appInstallTime = response.getInstallBeginTimestampSeconds();
boolean instantExperienceLaunched = response.getGooglePlayInstantParam();
whole code will be like this
referrerClient = InstallReferrerClient.newBuilder(this).build();
referrerClient.startConnection(new InstallReferrerStateListener() {
#Override
public void onInstallReferrerSetupFinished(int responseCode) {
switch (responseCode) {
case InstallReferrerClient.InstallReferrerResponse.OK:
// Connection established.
ReferrerDetails response = null;
try {
response = referrerClient.getInstallReferrer();
} catch (RemoteException e) {
e.printStackTrace();
}
String referrerUrl = response.getInstallReferrer();
long referrerClickTime = response.getReferrerClickTimestampSeconds();
long appInstallTime = response.getInstallBeginTimestampSeconds();
boolean instantExperienceLaunched = response.getGooglePlayInstantParam();
break;
case InstallReferrerClient.InstallReferrerResponse.FEATURE_NOT_SUPPORTED:
// API not available on the current Play Store app.
break;
case InstallReferrerClient.InstallReferrerResponse.SERVICE_UNAVAILABLE:
// Connection couldn't be established.
break;
}
}
#Override
public void onInstallReferrerServiceDisconnected() {
// Try to restart the connection on the next request to
// Google Play by calling the startConnection() method.
}
});

Google Drive API implementation Xamarin Android

Our application should have the functionality to save Application files to Google Drive. Of course, using the local configured account.
From Android API i tried to figure out some clue. But android API with Xamarin implementation seems very tough for me.
I have installed Google Play Services- Drive from Xamarin Components but there are no examples listed from which we can refer the flow and functionality.
The basic steps (see the link below for full details):
Create GoogleApiClient with the Drive API and Scope
Try to connect (login) the GoogleApiClient
The first time you try to connect it will fail as the user has not selected a Google Account that should be used
Use StartResolutionForResult to handle this condition
When GoogleApiClient is connected
Request a Drive content (DriveContentsResult) to write the file contents to.
When the result is obtained, write data into the Drive content.
Set the metadata for the file
Create the Drive-based file with the Drive content
Note: This example assumes that you have Google Drive installed on your device/emulator and you have registered your app in Google's Developer API Console with the Google Drive API Enabled.
C# Example:
[Activity(Label = "DriveOpen", MainLauncher = true, Icon = "#mipmap/icon")]
public class MainActivity : Activity, GoogleApiClient.IConnectionCallbacks, IResultCallback, IDriveApiDriveContentsResult
{
const string TAG = "GDriveExample";
const int REQUEST_CODE_RESOLUTION = 3;
GoogleApiClient _googleApiClient;
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
SetContentView(Resource.Layout.Main);
Button button = FindViewById<Button>(Resource.Id.myButton);
button.Click += delegate
{
if (_googleApiClient == null)
{
_googleApiClient = new GoogleApiClient.Builder(this)
.AddApi(DriveClass.API)
.AddScope(DriveClass.ScopeFile)
.AddConnectionCallbacks(this)
.AddOnConnectionFailedListener(onConnectionFailed)
.Build();
}
if (!_googleApiClient.IsConnected)
_googleApiClient.Connect();
};
}
protected void onConnectionFailed(ConnectionResult result)
{
Log.Info(TAG, "GoogleApiClient connection failed: " + result);
if (!result.HasResolution)
{
GoogleApiAvailability.Instance.GetErrorDialog(this, result.ErrorCode, 0).Show();
return;
}
try
{
result.StartResolutionForResult(this, REQUEST_CODE_RESOLUTION);
}
catch (IntentSender.SendIntentException e)
{
Log.Error(TAG, "Exception while starting resolution activity", e);
}
}
public void OnConnected(Bundle connectionHint)
{
Log.Info(TAG, "Client connected.");
DriveClass.DriveApi.NewDriveContents(_googleApiClient).SetResultCallback(this);
}
protected override void OnActivityResult(int requestCode, Result resultCode, Intent data)
{
base.OnActivityResult(requestCode, resultCode, data);
if (requestCode == REQUEST_CODE_RESOLUTION)
{
switch (resultCode)
{
case Result.Ok:
_googleApiClient.Connect();
break;
case Result.Canceled:
Log.Error(TAG, "Unable to sign in, is app registered for Drive access in Google Dev Console?");
break;
case Result.FirstUser:
Log.Error(TAG, "Unable to sign in: RESULT_FIRST_USER");
break;
default:
Log.Error(TAG, "Should never be here: " + resultCode);
return;
}
}
}
void IResultCallback.OnResult(Java.Lang.Object result)
{
var contentResults = (result).JavaCast<IDriveApiDriveContentsResult>();
if (!contentResults.Status.IsSuccess) // handle the error
return;
Task.Run(() =>
{
var writer = new OutputStreamWriter(contentResults.DriveContents.OutputStream);
writer.Write("Stack Overflow");
writer.Close();
MetadataChangeSet changeSet = new MetadataChangeSet.Builder()
.SetTitle("New Text File")
.SetMimeType("text/plain")
.Build();
DriveClass.DriveApi
.GetRootFolder(_googleApiClient)
.CreateFile(_googleApiClient, changeSet, contentResults.DriveContents);
});
}
public void OnConnectionSuspended(int cause)
{
throw new NotImplementedException();
}
public IDriveContents DriveContents
{
get
{
throw new NotImplementedException();
}
}
public Statuses Status
{
get
{
throw new NotImplementedException();
}
}
}
Ref: https://developers.google.com/drive/android/create-file

How to detect emergency call only in Xamarin?

Is there a way to detect if the phone, at the call try moment, can only make emergency calls (using Xamarin)?
This is something platform specific. Unfortunaelty I don't know any plugin for this, so you have to use the native API in Xamarin.
On Android it is the TelephonyManager as shown here: https://stackoverflow.com/a/14355706/1489968 It's Java, but can be easily translated to C#:
public class MainActivity : Activity
{
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
SetContentView(Resource.Layout.Main);
var telMng = (TelephonyManager) GetSystemService(TelephonyService);
var myPhoneStateListener = new MyPhoneStateListener();
myPhoneStateListener.ServiceStateChanged += (s, e) => Console.WriteLine("State: {0}", e);
telMng.Listen(myPhoneStateListener, PhoneStateListenerFlags.ServiceState);
}
}
public class MyPhoneStateListener : PhoneStateListener
{
public event EventHandler<ServiceState> ServiceStateChanged;
public override void OnServiceStateChanged(ServiceState serviceState)
{
base.OnServiceStateChanged(serviceState);
ServiceStateChanged?.Invoke(this, serviceState);
}
}
On iOS: Not sure if that information is available, never have seen it exposed via the SDK... (maybe add iOS tag to this question, or ask an iOS only question, answer might be in ObjC/Swift but you can translate it)
On Android: The info you are looking for is contained within the ServiceState of the phone:
var callState = new ServiceState ();
switch (callState.State) {
case PhoneState.InService:
{
var uri = Android.Net.Uri.Parse ("tel:555-2368"); // Jim Rockford's number ;-)
var intent = new Intent (Intent.ActionDial, uri);
StartActivity (intent);
break;
}
case PhoneState.EmergencyOnly:
{
Toast.MakeText (this, "Emergency Calls Only", ToastLength.Long).Show();
break;
}
case PhoneState.OutOfService:
{
Toast.MakeText (this, "Out of Service", ToastLength.Long).Show();
break;
}
case PhoneState.PowerOff:
{
Toast.MakeText (this, "Cell/Modem Power Off", ToastLength.Long).Show();
break;
}
default:
{
Toast.MakeText (this, "Should never be shown on a real device", ToastLength.Long).Show();
break;
}
}
Ref: http://developer.android.com/reference/android/telephony/ServiceState.html
For testing on the emulator, you can set the state to denied via the adb shell:
voice denied
data denied
Ref: https://developer.android.com/tools/devices/emulator.html

Android Auto - Callback when user connects mobile device

In regards to Android auto how can i get a callback when user has plugged the device into a car ? I'd like to trigger an action to occur based on when the user actually connects to android auto, is it possible ?
You should be able to get USB connection broadcast. From there you will have to write your own logic to figure out Android Auto is in foreground.
(may need to introduce a slight delay in case android auto takes time to come up. Launcher seems to be part of google play service)
Here is how I did it in my services onCreate method (right form the example code):
IntentFilter filter = new IntentFilter(CarHelper.ACTION_MEDIA_STATUS);
mCarConnectionReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
String connectionEvent = intent.getStringExtra(CarHelper.MEDIA_CONNECTION_STATUS);
mIsConnectedToCar = "media_connected".equals(connectionEvent);
LogHelper.i(TAG, "Connection event to Android Auto: ", connectionEvent,
" isConnectedToCar=", mIsConnectedToCar);
if(mIsConnectedToCar ) {
if(mService == null) {
bindMusicService();
if (mService != null) {
try {
initMediaMetaData();
toggleMediaPlaybackState(mService.isPlaying());
} catch (RemoteException e) {
Log.d(TAG, e.toString());
}
}
}
}
}
};
registerReceiver(mCarConnectionReceiver, filter);

Resources