How to make phone calls using Xamairn forms? - xamarin.forms

I'm new in xamarin and I want make a phone call directly (without opening the dialler). I tried with this example but it doesn't work.
Click Please help
public class PhoneCall_Droid : IPhoneCall
{
public void MakeQuickCall(string PhoneNumber)
{
try
{
var uri = Android.Net.Uri.Parse(string.Format("tel:{0}", PhoneNumber));
var intent = new Intent(Intent.ActionCall, uri);
Xamarin.Forms.Forms.Context.StartActivity(intent);
}
catch (Exception ex)
{
new AlertDialog.Builder(Android.App.Application.Context).SetPositiveButton("OK", (sender, args) =>
{
//User pressed OK
})
.SetMessage(ex.ToString())
.SetTitle("Android Exception")
.Show();
}
}
}

there are two error in your code above:
1.Xamarin.Forms.Forms.Context could not get the correct context.
you could defined a static variable in MainActiviy like :
public static MainActivity Instance;
protected override void OnCreate(Bundle savedInstanceState)
{
TabLayoutResource = Resource.Layout.Tabbar;
ToolbarResource = Resource.Layout.Toolbar;
base.OnCreate(savedInstanceState);
global::Xamarin.Forms.Forms.Init(this, savedInstanceState);
Instance = this;
LoadApplication(new App());
}
you also could use the Current Activity Plugin,you could refer to Current Activity
2.After Android6.0 you should requests the runtime permissions and the official doucument
here is a simple example:
[assembly: Xamarin.Forms.Dependency(typeof(PhoneCall_Droid))]
namespace App18.Droid
{
class PhoneCall_Droid: IPhoneCall
{
public void MakeQuickCall(string PhoneNumber)
{
try
{
if(ActivityCompat.CheckSelfPermission(MainActivity.Instance, Android.Manifest.Permission.CallPhone) != Android.Content.PM.Permission.Granted ){
ActivityCompat.RequestPermissions(MainActivity.Instance, new string[] {Android.Manifest.Permission.CallPhone }, 1);
return;
}
else
{
var uri = Android.Net.Uri.Parse(string.Format("tel:{0}", PhoneNumber));
var intent = new Intent(Intent.ActionCall, uri);
MainActivity.Instance.StartActivity(intent);
}
}
catch (Exception ex)
{
new AlertDialog.Builder(MainActivity.Instance).SetPositiveButton("OK", (sender, args) =>
{
//User pressed OK
})
.SetMessage(ex.ToString())
.SetTitle("Android Exception")
.Show();
}
}
}
}
and you also could to use the nugetpackage Plugin.Permissions to request runtime permissions(Permission.Location)
refer to Plugin.Permissions
finally you could call like
DependencyService.Get<IPhoneCall>().MakeQuickCall(phonenumber);

Related

Is there a way to use the camera functions in Xamarin Forms without downloading any extra NuGet Packages?

I am currently building a project which allows the user to take a photo of something and use that photo. I was wondering if there were any other methods out there that does not require me to download any Plugins or NuGet Packages?
You need to create a ICameraPickerService in Xamarin Forms :
public interface IPhotoPickerService
{
Task<byte[]> GetImageStreamAsync();
}
In iOS , create the CameraPickerService :
[assembly: Dependency(typeof(CameraPickerService))]
namespace DependencyServiceDemos.iOS
{
public class CameraPickerService: ICameraPickerService
{
TaskCompletionSource<byte[]> taskCompletionSource;
UIImagePickerController imagePicker;
public Task<byte[]> GetImageStreamAsync()
{
// Create and define UIImagePickerController
imagePicker = new UIImagePickerController
{
SourceType = UIImagePickerControllerSourceType.Camera,
MediaTypes = UIImagePickerController.AvailableMediaTypes(UIImagePickerControllerSourceType.Camera)
};
// Set event handlers
imagePicker.FinishedPickingMedia += OnImagePickerFinishedPickingMedia;
imagePicker.Canceled += OnImagePickerCancelled;
// Present UIImagePickerController;
UIWindow window = UIApplication.SharedApplication.KeyWindow;
var viewController = window.RootViewController;
viewController.PresentModalViewController(imagePicker, true);
// Return Task object
taskCompletionSource = new TaskCompletionSource<byte[]>();
return taskCompletionSource.Task;
}
void OnImagePickerFinishedPickingMedia(object sender, UIImagePickerMediaPickedEventArgs args)
{
UIImage image = args.EditedImage ?? args.OriginalImage;
if (image != null)
{
// Convert UIImage to .NET Stream object
NSData data;
if (args.ReferenceUrl.PathExtension.Equals("PNG") || args.ReferenceUrl.PathExtension.Equals("png"))
{
data = image.AsPNG();
}
else
{
data = image.AsJPEG(1);
}
Stream stream = data.AsStream();
UnregisterEventHandlers();
// Set the Stream as the completion of the Task
taskCompletionSource.SetResult(data.ToArray());
}
else
{
UnregisterEventHandlers();
taskCompletionSource.SetResult(null);
}
imagePicker.DismissModalViewController(true);
}
void OnImagePickerCancelled(object sender, EventArgs args)
{
UnregisterEventHandlers();
taskCompletionSource.SetResult(null);
imagePicker.DismissModalViewController(true);
}
void UnregisterEventHandlers()
{
imagePicker.FinishedPickingMedia -= OnImagePickerFinishedPickingMedia;
imagePicker.Canceled -= OnImagePickerCancelled;
}
}
}
Not forgetting to add permission in Info.plist :
<key>NSCameraUsageDescription</key>
<string>Use Camera</string>
In addition , iOS need to run in a physical device.
In Android , create the CameraPickerService :
[assembly: Dependency(typeof(CameraPickerService))]
namespace DependencyServiceDemos.Droid
{
public class CameraPickerService : ICameraPickerService
{
public Task<byte[]> GetImageStreamAsync()
{
// Define the Intent for getting images
Intent getImageByCamera = new Intent("android.media.action.IMAGE_CAPTURE");
// Start the camera (resumes in MainActivity.cs)
MainActivity.Instance.StartActivityForResult(
getImageByCamera,
MainActivity.PickImageId);
// Save the TaskCompletionSource object as a MainActivity property
MainActivity.Instance.PickImageTaskCompletionSource = new TaskCompletionSource<byte[]>();
// Return Task object
return MainActivity.Instance.PickImageTaskCompletionSource.Task;
}
}
}
Adding permission in AndroidMainfest.xml :
<uses-permission android:name= "android.permission.CAMERA" />
<uses-permission android:name= "android.permission.WRITE_EXTERNAL_STORAGE" />
Get Image data in MainActivity :
public class MainActivity : global::Xamarin.Forms.Platform.Android.FormsAppCompatActivity
{
internal static MainActivity Instance { get; private set; }
public int CAMERA_JAVA_REQUEST_CODE = 1;
protected override void OnCreate(Bundle savedInstanceState)
{
TabLayoutResource = Resource.Layout.Tabbar;
ToolbarResource = Resource.Layout.Toolbar;
base.OnCreate(savedInstanceState);
Instance = this;
global::Xamarin.Forms.Forms.Init(this, savedInstanceState);
LoadApplication(new App());
DependencyService.Register<ITextToSpeechService, TextToSpeechService>();
}
// Field, property, and method for Picture Picker
public static readonly int PickImageId = 1000;
public TaskCompletionSource<byte[]> PickImageTaskCompletionSource { set; get; }
protected override void OnActivityResult(int requestCode, Result resultCode, Intent intent)
{
base.OnActivityResult(requestCode, resultCode, intent);
if (requestCode == PickImageId)
{
if ((resultCode == Result.Ok) && (intent != null))
{
Bundle bundle = intent.Extras;
Bitmap bitmap = (Bitmap)bundle.Get("data");
//// Set the Stream as the completion of the Task
MemoryStream memoryStream = new MemoryStream();
bitmap.Compress(Bitmap.CompressFormat.Jpeg, 50, memoryStream);
PickImageTaskCompletionSource.SetResult(memoryStream.ToArray());
}
else
{
PickImageTaskCompletionSource.SetResult(null);
}
}
}
}
Finally , show image in ContentPage of Forms :
async void OnPickPhotoButtonClicked(object sender, EventArgs e)
{
(sender as Button).IsEnabled = false;
byte[] data = await DependencyService.Get<IPhotoPickerService>().GetImageStreamAsync();
MemoryStream stream = new MemoryStream(data);
if (stream != null)
{
image.Source = ImageSource.FromStream(() => stream) ;
}
(sender as Button).IsEnabled = true;
}
The effect :
Note : If want to pick a Photo from the Picture Library, you can have a look at this official document .

Circuit Breaker with gRPC

In a REST service adding a circuit breaker with hystrix, I could do the following:
#HystrixCommand(fallbackMethod = "getBackupResult")
#GetMapping(value = "/result")
public ResponseEntity<ResultDto> getResult(#RequestParam("request") String someRequest) {
ResultDto resultDto = service.parserRequest(someRequest);
return new ResponseEntity<>(resultDto, HttpStatus.OK);
}
public ResponseEntity<ResultDto> getBackupResult(#RequestParam("request") String someRequest) {
ResultDto resultDto = new ResultDto();
return new ResponseEntity<>(resultDto, HttpStatus.OK);
}
Is there something similar I can do for the gRPC call?
public void parseRequest(ParseRequest request, StreamObserver<ParseResponse> responseObserver) {
try {
ParseResponse parseResponse = service.parseRequest(request.getSomeRequest());
responseObserver.onNext(parseResponse);
responseObserver.onCompleted();
} catch (Exception e) {
logger.error("Failed to execute parse request.", e);
responseObserver.onError(new StatusException(Status.INTERNAL));
}
}
I solved my problem by implementing the circuit-breaker on my client. I used the sentinel library
To react on exceptions ratio for example I added this rule:
private static final String KEY = "callGRPC";
private void callGRPC(List<String> userAgents) {
initDegradeRule();
ManagedChannel channel = ManagedChannelBuilder.forAddress(grpcHost, grpcPort).usePlaintext()
.build();
for (String userAgent : userAgents) {
Entry entry = null;
try {
entry = SphU.entry(KEY);
UserAgentServiceGrpc.UserAgentServiceBlockingStub stub
= UserAgentServiceGrpc.newBlockingStub(channel);
UserAgentParseRequest request = UserAgentRequest.newBuilder().setUserAgent(userAgent).build();
UserAgentResponse userAgentResponse = stub.getUserAgentDetails(request);
} catch (BlockException e) {
logger.error("Circuit-breaker is on and the call has been blocked");
} catch (Throwable t) {
logger.error("Exception was thrown", t);
} finally {
if (entry != null) {
entry.exit();
}
}
}
channel.shutdown();
}
private void initDegradeRule() {
List<DegradeRule> rules = new ArrayList<DegradeRule>();
DegradeRule rule = new DegradeRule();
rule.setResource(KEY);
rule.setCount(0.5);
rule.setGrade(RuleConstant.DEGRADE_GRADE_EXCEPTION_RATIO);
rule.setTimeWindow(60);
rules.add(rule);
DegradeRuleManager.loadRules(rules);
}

Android New Version Available - App Update Dialog Using Json From Own Server

I want to show dialogue when new version is available.
I want to make a json file into my web server, and I will manually update my app version in json file. and my app will parse this json file and will notify users and showing dialogue box to update my app from playstore link by clicking Update button.
I don't want to make this with firebase.
public class ForceUpdateAsync extends AsyncTask<String, String, JSONObject>{
private String latestVersion;
private String currentVersion;
private Context context;
public ForceUpdateAsync(String currentVersion, Context context){
this.currentVersion = currentVersion;
this.context = context;
}
#Override
protected JSONObject doInBackground(String... params) {
try
{
latestVersion = Jsoup.connect("https://play.google.com/store/apps/details?id="+context.getPackageName()+"&hl=en")
.timeout(30000)
.userAgent("Mozilla/5.0 (Windows; U; WindowsNT 5.1; en-US; rv1.8.1.6) Gecko/20070725 Firefox/2.0.0.6")
.referrer("http://www.google.com")
.get()
.select("div[itemprop=softwareVersion]")
.first()
.ownText();
} catch (IOException e) {
e.printStackTrace();
}
return new JSONObject();
}
#Override
protected void onPostExecute(JSONObject jsonObject) {
if(latestVersion!=null){
if(!currentVersion.equalsIgnoreCase(latestVersion)){
// Toast.makeText(context,"update is available.",Toast.LENGTH_LONG).show();
if(!(context instanceof SplashActivity)) {
if(!((Activity)context).isFinishing()){
showForceUpdateDialog();
}
}
}
}
super.onPostExecute(jsonObject);
}
public void showForceUpdateDialog(){
AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(new ContextThemeWrapper(context,
R.style.DialogDark));
alertDialogBuilder.setTitle(context.getString(R.string.youAreNotUpdatedTitle));
alertDialogBuilder.setMessage(context.getString(R.string.youAreNotUpdatedMessage) + " " + latestVersion + context.getString(R.string.youAreNotUpdatedMessage1));
alertDialogBuilder.setCancelable(false);
alertDialogBuilder.setPositiveButton(R.string.update, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
context.startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("market://details?id=" + context.getPackageName())));
dialog.cancel();
}
});
alertDialogBuilder.show();
}
}
after that in your splash activity just use this code
public void forceUpdate()
{
PackageManager packageManager = this.getPackageManager();
PackageInfo packageInfo = null;
try {
packageInfo = packageManager.getPackageInfo(getPackageName(),0);
} catch (PackageManager.NameNotFoundException e) {
e.printStackTrace();
}
String currentVersion = packageInfo.versionName;
new ForceUpdateAsync(currentVersion,BaseActivity.this).execute();
}

Can't retrieve Firebase InstanceId Token after updating to newest library

Okay so after updating to the newest firebase messaging library, I can't seem to retrieve the token. I t said in the docs that it should not be run in the main thread but when I tried, it still didn't work. So I simply removed it. What could I be doing wrong?
Below is my try/catch code.
String device_token;
try {
device_token = FirebaseInstanceId.getInstance().getToken(R.string.sender_id, "FCM");
student_token_reference = FirebaseDatabase.getInstance().getReference().child("MakeUpArtists_Info").child(uid);
student_token_reference.child("device_token").setValue(device_token).addOnSuccessListener(new OnSuccessListener<Void>() {
#Override
public void onSuccess(Void aVoid) {
DatabaseReference check_variablesRef = FirebaseDatabase.getInstance().getReference().child("MakeUpArtists_Info").child(FirebaseAuth.getInstance().getCurrentUser().getUid()).child("Verification");
check_variablesRef.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
String id_card = dataSnapshot.child("id_card").getValue().toString();
String image = dataSnapshot.child("image").getValue().toString();
if (id_card.equals("Not yet") && image.equals("Not yet")) {
Toast.makeText(LoginActivity.this, "Please finish uploading your documents", Toast.LENGTH_SHORT).show();
Intent id_card_intent = new Intent(LoginActivity.this, IDcard.class);
startActivity(id_card_intent);
finish();
} else if (id_card.equals("Received") && image.equals("Received")) {
Intent intentMain = new Intent(LoginActivity.this, MainActivity.class);
intentMain.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
startActivity(intentMain);
finish();
} else if (id_card.equals("Received") && image.equals("Not yet")) {
Toast.makeText(LoginActivity.this, "Please upload your profile picture", Toast.LENGTH_SHORT).show();
Intent success_intent = new Intent(LoginActivity.this, DisplayProfile.class);
startActivity(success_intent);
finish();
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
}
});
} catch (IOException e) {
e.printStackTrace();
}
Any help would be greatly appreciated!
The Firebase Release Notes for the June 28 release recommend using FirebaseInstanceId.getInstance().getInstanceId(). Here is an example (as you requested in comments) of how to do that:
FirebaseInstanceId.getInstance().getInstanceId().addOnCompleteListener(
new OnCompleteListener<InstanceIdResult>() {
#Override
public void onComplete(Task<InstanceIdResult> task) {
if (task.isSuccessful()) {
final InstanceIdResult iidResult = task.getResult();
final String token = iidResult.getToken();
Log.d(TAG, "token=" + token);
// process token as you need...
} else {
Log.e(TAG, "get IID/token failed", task.getException());
}
}
});

Mobile map package returns null for map

I downloaded Arcgis sample mmpk file and even I made a mmpk myself.
In both files I have 1 map(checked by debug) but when I try load the map (with codes in Esri guide page) it returns null for map.
Good to say that I can show online map in my map view and android studio shows no warning or error.
import static n.k.masoud.sbmap.R.id.mapView;
public class ActivityMain extends AppCompatActivity {
private MapView mMapView;
private ArcGISMap map;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mMapView = (MapView) findViewById(mapView);
code and file from main site
try {File mmpkFile = new File(Environment.getExternalStorageDirectory(),"devlabs-package.mmpk");
String mmpkPath = mmpkFile.getAbsolutePath();
final MobileMapPackage mobileMapPackage=new MobileMapPackage(mmpkPath);
mobileMapPackage.addDoneLoadingListener(new Runnable() {
#Override
public void run() {
this if gets false
if (mobileMapPackage.getLoadStatus() == LoadStatus.LOADED) {
showMessage(String.format("Number of maps = %d", mobileMapPackage.getMaps().size()));
map = mobileMapPackage.getMaps().get(0);
} else {
dealWithLoadFailure();
}
}
});
mobileMapPackage.loadAsync();
}
catch (Exception err){
Log.e("TAG", "onCreate: "+err);
}
map.addDoneLoadingListener(new Runnable() {
#Override
public void run() {
if (map.getLoadStatus() == LoadStatus.LOADED) {
Log.e("TAG", "run: map loaded ok" );
// Once map is loaded, can check its properties and content
if (map.getBookmarks().size() > 0) {
}
} else {
dealWithLoadFailure();
}
}
});
map.loadAsync();
As I told part below works correctly
// for online maps
// ArcGISMap map = new ArcGISMap(Basemap.Type.TOPOGRAPHIC, 29.453826, 60.852134,12);
mMapView.setMap(map);
mMapView.addLayerViewStateChangedListener(new LayerViewStateChangedListener() {
#Override
public void layerViewStateChanged(LayerViewStateChangedEvent layerViewStateChangedEvent) {
// Each layer may have more than one layer view state.
StringBuilder layerStatuses = new StringBuilder();
for (LayerViewStatus status : layerViewStateChangedEvent.getLayerViewStatus()) {
if (layerStatuses.length() > 0) {
layerStatuses.append(",");
} layerStatuses.append(status.name());
}
showMessage(String.format("Layer '%s' status=%s", layerViewStateChangedEvent.getLayer().getName(), layerStatuses.toString()));
} });
}
#Override
protected void onPause(){
mMapView.pause();
super.onPause();
}
#Override
protected void onResume(){
super.onResume();
mMapView.resume();
}
}
if the line
if (mobileMapPackage.getLoadStatus() == LoadStatus.LOADED)
is returning false, then the mobile map package is not loaded and won't contain any maps.
In your dealWithLoadFailure() function you can retrieve the load error:
mobileMapPackage.getLoadError()
and see what it is. It should tell you what the error causing the load failure is.
One of my friends tried this way but didn't got any result just like me.
So he changed the official guide code to this and got well response.
I think he got code from Internet , so I don't know about it's copyright permission.
private void setupMobileMap() {
if (mMapView != null) {
File mmpkFile = new File(Environment.getExternalStorageDirectory(), "devlabs-package.mmpk");
final MobileMapPackage mapPackage = new MobileMapPackage(mmpkFile.getAbsolutePath());
mapPackage.addDoneLoadingListener(new Runnable() {
#Override
public void run() {
// Verify the file loaded and there is at least one map
if (mapPackage.getLoadStatus() == LoadStatus.LOADED && mapPackage.getMaps().size() > 0) {
mMapView.setMap(mapPackage.getMaps().get(0));
} else {
// Error if the mobile map package fails to load or there are no maps included in the package
//setupMap();
//Log for Error
}
}
});
mapPackage.loadAsync();
}
}

Resources