I can't get OnNewIntent to fire. I've read dozens of articles on the issue and tried all combinations of code.
Regardless of whether I use LaunchMode.SingleTask or SingleTop it won't fire and always passes through the OnCreate method.
What am I doing wrong here? Am I missing something? What do I need to add to get it to work?
using Android.App;
using Android.Content;
using Android.Content.PM;
using Android.OS;
using Android.Runtime;
using System;
using System.Threading.Tasks;
using Xamarin.Forms;
using static MyApp.ClipboardMgr;
namespace MyApp.Droid
{
//[Activity(Label = "SplashActivity")]
[Activity(LaunchMode = LaunchMode.SingleTask, Theme = "#style/Theme.Splash",
MainLauncher = true, NoHistory = true)]
//Can't get this to work with LaunchMode.SingleTop or SingleTask. Always creates a new instance.
[IntentFilter(new[] { Intent.ActionProcessText },
Categories = new[] { Intent.CategoryDefault },
DataMimeType = #"text/plain", Icon = "#drawable/icon", Label = "MyApp")]
public class SplashActivity : Activity
{
protected override void OnCreate(Bundle savedInstanceState)
{
try
{
//taking these out for readability
//AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;
//TaskScheduler.UnobservedTaskException += TaskScheduler_UnobservedTaskException;
//AndroidEnvironment.UnhandledExceptionRaiser += AndroidEnvironment_UnhandledExceptionRaiser;
base.OnCreate(savedInstanceState);
// Create your application
StartActivity(typeof(MainActivity));
//don't want to do this here, better to do it in event
if (Intent.Action == Intent.ActionProcessText)
{
//always comes here
HandleProcessTextIntent();
}
}
catch(Exception e)
{
App.LogException(e);
throw;
}
}
/// <summary>
/// this is not firing!
/// </summary>
/// <param name="intent"></param>
protected override void OnNewIntent(Intent intent)
{
base.OnNewIntent(intent);
HandleProcessTextIntent();
}
void HandleProcessTextIntent()
{
string input = Intent.GetStringExtra(Intent.ExtraProcessText).Trim();
if (input == string.Empty)
return;
ClipMgr.SetText(input);
}
}
}
You didn't miss anything since when I test with my own intent to start your activity, it works well and the OnNewIntent() is called when SingleTask or SingleTop used, here's how I call the activity from another project(I did this in native Android):
ComponentName component = new ComponentName("com.example.textHandlerDemo", "com.example.textHandlerDemo.TextHandlerActivity");
Intent intent = new Intent();
intent.setAction(Intent.ACTION_PROCESS_TEXT);
intent.setComponent(component);
startActivity(intent);
I did some research and find something that may explain why the OnNewIntent() never gets fired:
According to the guidance of ACTION_PROCESS_TEXT, it mentioned:
You can use this as a hint to offer the ability to return altered text to the sending app, replacing the selected text. This works as your Activity was actually started with startActivityForResult()
So, when you click your app's label in the floating text selection toolbar, Android will start your activity registered with ActionProcessText with startActivityForResult(), and by using startActivityForResult(), your activity will be started as a sub-activity of current activity(implied from Android doc of startActivityForResult), that is to say, rather than redirecting to your app which is already running, Android will put your activity into current app's stack.
This way, your target activity will still be called from OnCreate() since it's isolated from your running app.
Moreover, the floating text selection toolbar is used to provide a quick in-app experience for text operations like translation as mentioned in this blog, I didn't find any swich to enable/disable redirect to app, you may need to handle the intent in both OnCreate() and OnNewIntent() if you're using LaunchMode.SingleTask or SingleTop.
Related
i'm working on an android app at the moment that has the purpose of playing a particular song at exactly midnight. I know that there might already be apps in the appstore that serve that purpose, but I'm new to coding and wanted to try to program the app myself.
So now I reached the point where I don't know what to do anymore. I tried debugging the App on my LG H818P running Android 6.0. It posted, The Icon, the Name and everything were correct, but i didn't play the song, even when i set the time when it should've played it to two minutes after the start if the building.
So that's the code of the MainActivity.cs in Visual Studio 2017, can anyone find any errors?
using Android.App;
using Android.Widget;
using Android.OS;
using System;
using Android.Media;
namespace Name of the App
{
[Activity(Label = "Name of the App", MainLauncher = true)]
public class MainActivity : Activity
{
string text = "status";
protected void onCreate(Bundle savedInstanceState)
{
}
public void main()
{
try
{
string systemtime = DateTime.Now.ToString();
for (int i = 0; i > 0; i++)
{
if (systemtime == "09:07:00 pm")
{
StartPlayer();
player.Start();
}
}
}
catch
{
text = "Error!";
}
}
protected MediaPlayer player;
public void StartPlayer()
{
if (player == null)
{
player = new MediaPlayer();
player.SetDataSource("Ressources.raw.file2beplayed.mp3");
player.Prepare();
player.Start();
text = "Playing!";
}
else
{
player.Reset();
player.SetDataSource("Ressources.raw.file2beplayed.mp3");
player.Prepare();
player.Start();
}
}
}
}
As I said, I'm a Noob in coding, so sorry for the maybe ugly code :)
Thanks for your replies!
The default format for ToString in a DateTime is MM/dd/yyyy, so your comparation systemtime == "09:07:00 pm" will never be true.
You can use a TimeSpan and the property TimeOfDay from DateTime;
if(DateTime.Now.TimeOfDay == new Timespan(21,7,0))
//...
Also, your loop will never be executed as you initialize i as 0, so at the first check i will not be greater than 0 so the loop isn't executed.
Finally, Android does not use the main function, is an special type of program, your initialization code should be in the OnCreate function, but if you create an infinite loop in that function Android will close the application as it will not finish it's initialization, you need to use a timer and check the condition each second.
I am working on a small Xamarin.Forms webview application. This is a follow up question to the one answered previously, xamarin-forms-making-webview-go-back
So I have a toolbar and a back button implemented and working. But when I run the program with the emulator already open(im using Genymotion), the program runs and shows the toolbar along with the back button...but no webview will display.
But heres the strange thing, sometimes when I run the program when the emulator is in sleep mode and then switch it back on the program works perfectly. Also, when I tested it on iOS it just showed the toolbar and no webview at all! More often then not, the emulator just wont show the webView. I have also tested this on my Android device and the same thing happens, itll show the toolbar but not the webview.
Abit confusing I know but can anyone help me out with this.
I will attach my code below:
App.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Xamarin.Forms;
namespace WebView_form
{
public class App : Application
{
public App()
{
//const string URL = "http://www.google.com";
MainPage = new NavigationPage(new WebPage());
}
protected override void OnStart()
{
// Handle when your app starts
}
protected override void OnSleep()
{
// Handle when your app sleeps
}
protected override void OnResume()
{
// Handle when your app resumes
}
}
}
WebPage.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection.Emit;
using System.Text;
using Xamarin.Forms;
namespace WebView_form
{
public class WebPage : ContentPage
{
private WebView webView;
public WebPage()
{
webView = new WebView
{
Source = "https://www.google.com"
};
// toolbar
ToolbarItems.Add(new ToolbarItem("Back", null, () =>
{
webView.GoBack();
}));
Content = new StackLayout
{
Children = { webView }
};
}
}
}
If anyone can help me out, it'd be great.
Set the VerticalOptions to FillAndExpand and do the same for HorizontalOptions if that's not working.
Probably the WebView is getting a zero size height because when the layout happens the view is still empty.
So change the code in your WebPage.cs like this;
// ... Other code
public WebPage()
{
webView = new WebView
{
Source = "https://www.google.com",
VerticalOptions = LayoutOptions.FillAndExpand,
HorizontalOptions = LayoutOptions.FillAndExpand
};
// toolbar
ToolbarItems.Add(new ToolbarItem("Back", null, () =>
{
webView.GoBack();
}));
Content = new StackLayout
{
Children = { webView }
};
}
// ... Other code
Another thing to consider: If you are responding to the WebView.Navigating event, be sure to not set its args.Cancel to true if the page loaded is the WevView.Source. The iOS implementation of WebView.Navigating fires when the WebView.Source is loaded but the Android implementation does not. If you set args.Cancel to true when the page in question is the WebView.Source, the WebView will be blank.
Set this into your Info.plist to bypass the App Transport Security check. Visit https://developer.apple.com/documentation/bundleresources/information_property_list/nsapptransportsecurity for more info.
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
</dict>
Note: My URL is already HTTPS, not sure why it's still blocked.
I'm pretty new to xamarin / android development but this is pretty much what I'm trying conceptually:
Have a main activity that checks whether or not a user is already logged in
If the user is logged in, start the MainAppActivity
If the user is not logged in, start the OnboardingActivity
The reason I think these should be in different activities is for general design reasons (separation of concerns etc) - but also because both activities have different themes. (The Onboarding process has no title bar)
In code, this should be pretty much what I need:
[Activity(Label = "MyApp", MainLauncher = true, Icon = "#drawable/icon", Theme = "#android:style/Theme.Black.NoTitleBar")]
public class MainActivity : Activity
{
private readonly TransactionService _transactionService;
public MainActivity()
{
var isLoggedIn = true; // This will be loaded from somewhere
if(isLoggedIn)
{
var intent = new Intent(this, typeof(MainAppActivity));
StartActivity(intent);
}
else
{
var intent = new Intent(this, typeof(OnboardingActivity));
StartActivity(intent);
}
}
}
However, this code just throws an unspecified exception.
If I try the same thing during the protected override void OnCreate(Bundle bundle) process, I get an exception as well.
However, when I bind something like that to a button event and click it manually, it will work. (That is not my intent, but to test there is nothing wrong with my activities)
So, question is, how do I do something like this?
Edit: Here is the stacktrace if I try it in the constructor:
0x29 in System.Diagnostics.Debugger.Mono_UnhandledException_internal C#
0x1 in System.Diagnostics.Debugger.Mono_UnhandledException at /Users/builder/data/lanes/1978/f98871a9/source/mono/mcs/class/corlib/System.Diagnostics/Debugger.cs:122,4 C#
0x6 in Android.Runtime.UncaughtExceptionHandler.UncaughtException at /Users/builder/data/lanes/1978/f98871a9/source/monodroid/src/Mono.Android/src/Runtime/UncaughtExceptionHandler.cs:35,4 C#
0x1C in Java.Lang.Thread.IUncaughtExceptionHandlerInvoker.n_UncaughtException_Ljava_lang_Thread_Ljava_lang_Throwable_ at /Users/builder/data/lanes/1978/f98871a9/source/monodroid/src/Mono.Android/platforms/android-21/src/generated/Java.Lang.Thread.cs:221,5 C#
0x1D in object.b8bd1d31-3e2e-454d-bd94-9d5dea40eddb C#
I have not used xamarin, so I could be wrong.
FYR, on native android, you should do that in the onCreate of your MainActivity instead of Constructor
The speech is working fine on my real device.
using System;
using Android.App;
using Android.Content;
using Android.Runtime;
using Android.Views;
using Android.Widget;
using Android.OS;
using Android.Speech.Tts;
namespace App7
{
[Activity(Label = "App7", MainLauncher = true, Icon = "#drawable/icon")]
public class MainActivity : Activity, TextToSpeech.IOnInitListener
{
public TextToSpeech SpeechText
{
get;
set;
}
int count = 1;
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
// Set our view from the "main" layout resource
SetContentView(Resource.Layout.Main);
// create text to speech object to use synthesize and speak functions.
// first parameter: context
// second parameter: object implemeting TextToSpeech.IOnInitListener
this.SpeechText = new TextToSpeech(this, this);
Button testButton = FindViewById<Button>(Resource.Id.button1);
testButton.Click += delegate
{
this.SpeechText.Speak("Hello World, You shall not pass", QueueMode.Flush, null);
};
// Get our button from the layout resource,
// and attach an event to it
Button button = FindViewById<Button>(Resource.Id.MyButton);
button.Click += delegate { button.Text = string.Format("{0} clicks!", count++); };
}
public void OnInit(OperationResult status)
{
// here you can setup language settings
if (status.Equals(OperationResult.Success))
Toast.MakeText(this, "Text To Speech Succeed!", ToastLength.Long).Show();
else
Toast.MakeText(this, "Text To Speech Fail", ToastLength.Long).Show();
}
}
}
The warning is on this line:
this.SpeechText.Speak("Hello World, You shall not pass", QueueMode.Flush, null);
Under this line there is a green line and the warning message is:
Warning 1 'Android.Speech.Tts.TextToSpeech.Speak(string, Android.Speech.Tts.QueueMode, System.Collections.Generic.IDictionary)' is obsolete: 'deprecated'
Tried to google didn't find anything.
I can ignore it but I would like to know what does it mean ? And how can I fix it ?
It means this overload is deprecated in Xamarin (because Google marked it as deprecated as of API level 21).
Use the other two overloads (1, 2) that aren't deprecated if the warning bothers you and your target API level allows it, or just ignore the warning.
I have this code:
using System;
using Android.App;
using Android.Content;
using Android.Runtime;
using Android.Views;
using Android.Widget;
using Android.OS;
using Android.Speech.Tts;
using System.Collections.Generic;
namespace SayItAndroid{ [Activity (Label = "SayItAndroid", MainLauncher = true)]
public class Activity1 : Activity, TextToSpeech.IOnInitListener
{
int count = 1;
TextToSpeech mTts;
public void OnInit (int status)
{
Console.WriteLine ("Listening to text to speech");
}
protected override void OnCreate (Bundle bundle)
{
base.OnCreate (bundle);// Set our view from the "main" layout resource
SetContentView (Resource.Layout.Main);
Intent checkIntent = new Intent();
checkIntent.SetAction(TextToSpeech.Engine.ActionCheckTtsData);
StartActivityForResult(checkIntent, 100); // Get our button from the layout resource, // and attach an event to it
Button button = FindViewById<Button> (Resource.Id.myButton);
button.Click += delegate
{
string myText1 = "Did you sleep well?";
string myText2 = "I hope so, because it's time to wake up.";
mTts.Speak(myText1, QueueMode.Add, new Dictionary<string, string>());
mTts.Speak(myText2, QueueMode.Flush, new Dictionary<string, string>());
};
}
protected override void OnActivityResult (int requestCode, Result resultCode, Intent data)
{
base.OnActivityResult (requestCode, resultCode, data);
if(requestCode == 100)
{
mTts = new TextToSpeech(this, this);
}
}
}}
But on the two places i have Resource im getting red line error under the Resource:
Error 1 The name 'Resource' does not exist in the current context
How can i solve it ?
Thanks.
The reason that Resource cannot be found is 9 out of 10 times because the Resource is not in the same namespace as the file you are referring it from.
As stated on this page by Xamarin, the project's default namespace is used to store the generated Resource class file in.
If your class resides in another namespace things break.
Hope that clears things up for you.