My Xamarin Android app keeps restarting itsself - android

I've an app that checks version compatibility at startup from within the main activity's OnCreate function. Since Android doesn't (to my knowledge) have a modal dialog, if the version is not compatible I show an AlertDialog via AlertDialog.Builder and set the neutral button action to shut down the app. Unfortunately this causes the app to restart instead of shutting down. Could someone help me get the app to shut down please?
This is being tested on Android 7.0, but also needs to run on Android 4.2.2.
public class Activity1 : FragmentActivity {
protected override void OnCreate(Bundle bundle) {
base.OnCreate(bundle);
if (!versionCheck.Success) {
ShowNotesReadonlyDialog("Version Incompatibility", versionCheck.Message, new Action(() => ShutdownApplication()) );
return;
}
}
private void ShutdownApplication() {
this.Finish();
// -- I've tried all the things below with the same result.
//this.FinishAffinity();
//this.Dispose();
//global::Android.OS.Process.KillProcess(global::Android.OS.Process.MyPid());
}
private void ShowNotesReadonlyDialog(String title, String message, Action action) {
AlertDialog.Builder dialog = new AlertDialog.Builder(this);
LayoutInflater inflater = (LayoutInflater)this.GetSystemService(Context.LayoutInflaterService);
View layout = inflater.Inflate(Resource.Layout.GenericTextViewLayout, FindViewById<ViewGroup>(Resource.Id.GenericTextViewDialogRoot));
dialog.SetTitle(title);
dialog.SetView(layout);
TextView label = layout.FindViewById<TextView>(Resource.Id.GenericTextViewMessageLabel);
label.Text = message;
dialog.SetNeutralButton("Close", (o, e) => {
if (null != action) {
action.Invoke();
}
dialog.Dispose();
});
dialog.SetCancelable(false);
AlertDialog window = dialog.Create();
WindowManagerLayoutParams p = new WindowManagerLayoutParams();
p.CopyFrom(window.Window.Attributes);
p.Width = 900;
p.Height = WindowManagerLayoutParams.WrapContent;
window.Show();
window.Window.Attributes = p;
}
}
I've placed breakpoints in several lifecycle events. After calling Finish() the following events are called on the Activity:
OnStop()
OnCreate()
OnStart()
Additionally, the Activity disappears from the screen when Finish() is called, but pressing the "window manager" hardware key shows that the application is still running. Tapping the window shows it on screen.

Related

In AlertDialog - Unable to add window -- token null is not valid; is your activity running?

I have created a custom notifcation control using AlertDialog which will displays at the Top. It works fine for some devices like Samsung Galaxy S7,S8 where it is running with Android 7.0 OS. However It doesn't works on some mobile devices with same OS running.
It is throwing "Unable to add window -- token null is not valid; is your activity running?" in Show Method. Any help would be really appreciated. The below is the code snippit. The syntax is xamarin. However the logics are same as native android.
public class MyNotificationControl
{
AlertDialog b;
public MyNotificationControl(Android.Content.Context context)
{
AlertDialog.Builder builder = new AlertDialog.Builder(Android.App.Application.Context);
LayoutInflater inflater = (LayoutInflater)context.GetSystemService(Context.LayoutInflaterService);
View dialogView = inflater.Inflate(Resource.Layout.mynotification_layout, null);
builder.SetView(dialogView);
b = builder.Create();
b.Window.SetType(WindowManagerTypes.Toast);
Window window = b.Window;
window.SetFlags(WindowManagerFlags.NotTouchModal, WindowManagerFlags.NotTouchModal);
window.ClearFlags(WindowManagerFlags.DimBehind);
window.SetGravity(GravityFlags.Top);
window.SetBackgroundDrawableResource(Android.Resource.Color.Transparent);
}
public void Show()
{
try
{
b.Show();
}
catch(Exception ex)
{
//Here is my exception occurs. Unable to add window -- token null is not valid; is your activity running?
}
}
public void Close()
{
b?.Dismiss();
}
}
Pass the current activity context instead Application context in AlertDialog.Builder().
Set the AlertDialog type to WindowManagerTypes.ApplicationPanel intead of Toast
AlertDialog.Builder builder = new AlertDialog.Builder(context);//current activity.
b.Window.SetType(WindowManagerTypes.ApplicationPanel);
Please refer to this.
This exception occurred while app was trying to notify user from the background thread by opening a Dialog.
Do like this:
RunOnUiThread(() => {
if (!IsFinishing) {
//to call the show method
}
});
Or you can refer to this.
for fragment just use
AlertDialog.Builder builder = new AlertDialog.Builder(this.getContext());

Display Dialog after uncaught exception

I tried to start an activity with an implicit intent after an uncaught exception with the unCaughtExceptionHandler. The intent should start an Activity as a Dialog in the same app that has crashed. This corresponds to the example listed in this thread:
Need to handle uncaught exception and send log file
I call the original unCaughtExceptionHandler at the end of my own handler procedure, like this:
public class ThisApplication extends Application
{
Thread.UncaughtExceptionHandler originalUncaughtExceptionHandler;
#Override
public void onCreate ()
{
originalUncaughtExceptionHandler = Thread.getDefaultUncaughtExceptionHandler();
Thread.setDefaultUncaughtExceptionHandler (new Thread.UncaughtExceptionHandler()
{
#Override
public void uncaughtException (Thread thread, Throwable e)
{
handleUncaughtException (thread, e);
}
});
super.onCreate();
}
public void handleUncaughtException (Thread thread, Throwable e)
{
e.printStackTrace();
Intent intent = new Intent ();
intent.setAction ("de.mydomain.myapp.action.PROCESS_LOG");
intent.setFlags (Intent.FLAG_ACTIVITY_NEW_TASK);
if (intent.resolveActivity(getPackageManager()) == null) {
Log.d("ThisApplication","No receiver");
} else {
Log.d("ThisApplication", "Intent start");
startActivity(intent);
}
originalUncaughtExceptionHandler.uncaughtException(thread, e);
}
}
The result is, that after an Exception the standard Dialog is displayed that says something like "Unfortunately App xxx was closed". Behind that Dialog, in the background, I can see my Dialog that should be started with this intent "PROCESS_LOG". So obviously is was started, but the problem is, that after the standard Dialog has been closed, my custom dialog also closes. If I add
android:launchMode="singleInstance"
in the manifest of the dialog activity, the dialog is hidden, too, but it can be activated again when the app is selected from the recent apps menu. This seems to me as if the dialog is not started fully independently from the former app process/task.
Can somebody say what I did wrong?
This is the manifest part of the dialog activity:
<activity
android:name=".ProcessLogActivity"
android:windowSoftInputMode="stateHidden"
android:theme="#style/ProcessLogActivity"
android:process=":report_process"
>
<intent-filter>
<action android:name="de.mydomain.myapp.action.PROCESS_LOG" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
The corresponding style:
<style name="ProcessLogActivity" parent="#style/Theme.AppCompat.Light.Dialog">
</style>
This is the Dialog Activity class:
public class ProcessLogActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature (Window.FEATURE_NO_TITLE);
setFinishOnTouchOutside (false);
Log.d("ThisApplication", "Intent received");
setContentView(R.layout.activity_process_log);
}
}
To post a full message (comment is too short), here the full class and configuration:
I tried to use ACRA with the built-in dialog-functionality, but I could not get it work. But the built-in funtionality to show a "Toast" works! So that's why I ask myself where the problem is showing the dialog. I use the following #ReportCrashed Annotation for testing:
#ReportsCrashes(
formUri = "http://yourserver.com/yourscript",
mode = ReportingInteractionMode.NOTIFICATION,
resDialogText = R.string.app_name,
resNotifTickerText = R.string.app_name,
resNotifTitle = R.string.app_name,
resNotifText = R.string.app_name
)
Inside my own Application-Class I use the following initialisation:
public class ThisApplication extends Application {
#Override
protected void attachBaseContext(Context base) {
super.attachBaseContext(base);
final ConfigurationBuilder configurationBuilder = new ConfigurationBuilder(this);
configurationBuilder.setBuildConfigClass(BuildConfig.class);
final ACRAConfiguration config;
try {
config = configurationBuilder.build();
ACRA.init(this, config);
} catch (ACRAConfigurationException e) {
e.printStackTrace();
}
}
}
My App uses two different Build flavors and the two build types "Debug" and "Release".
When I throw an unhandled exception the app closes and a dialog is only sometimes displayed for a very short moment (less than half a second) before the whole app is closed without any dialog.
Any ideas?...
EDIT: The above Annotation was the try with a Notification, that also does not work. The notification is also displayed only for a very short moment and then disappears immediately. The dialog Annotation was:
#ReportsCrashes(
formUri = "http://yourserver.com/yourscript",
mode = ReportingInteractionMode.DIALOG,
resDialogText = R.string.app_name
)
This has the effect described above.
The Problem was - at least in the case of the ACRA-Dialog - that it is not working as the app is debugged with the built-in functionality from android studio. So you have to start the app on the android test system (on the debugging device) without support from android studio IDE. When you do that and an exception is thrown, the ACRA-Dialog appears as it should.

read a nfc chip after the users clicks a button

is it possible to start reading from a nfc-chip after pressing a button. After pushing the button there should be a message like "please hold your nfc chip close to the device..". I only see tutorials, which show how to start the application when holding a nfc chip to the device (onNewIntent).
Second Question. What if the application is already running and i hold the nfc chip next to my device? Is it forcing a destroy and then launches again?
Thanks!
Regarding the first part of your question, you could use a flag within your activity that indicates the state of your application (ready to write/message is showing, not ready to write/message not showing). YOu can find a simple example here:
private static final int DIALOG_WRITE = 1;
private boolean mWrite = false; // write state
public void onCreate(Bundle savedInstanceState) {
[...]
// Set action for "Write to tag..." button:
mMyWriteButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
// Switch to write mode:
mWrite = true;
// Show a dialog when we are ready to write:
showDialog(DIALOG_WRITE);
}
});
[...]
}
protected Dialog onCreateDialog(int id, Bundle args) {
switch (id) {
case DIALOG_WRITE:
// A dialog that we show when we are ready to write to a tag:
return new AlertDialog.Builder(this)
.setTitle("Write to tag...")
.setMessage("Touch tag to start writing.")
.setCancelable(true)
.setNeutralButton(android.R.string.cancel, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface d, int arg) {
d.cancel();
}
})
.setOnCancelListener(new DialogInterface.OnCancelListener() {
public void onCancel(DialogInterface d) {
mWrite = false;
}
}).create();
}
return null;
}
// You would call this method from onCreate/onStart/onResume/onNewIntent
// or from whereever you want to process an incoming intent
private void resolveIntent(Intent data, boolean foregroundDispatch) {
String action = data.getAction();
if (NfcAdapter.ACTION_TECH_DISCOVERED.equals(action)
|| NfcAdapter.ACTION_TAG_DISCOVERED.equals(action)
|| NfcAdapter.ACTION_NDEF_DISCOVERED.equals(action)) {
// The reference to the tag that invoked us is passed as a parameter (intent extra EXTRA_TAG)
Tag tag = data.getParcelableExtra(NfcAdapter.EXTRA_TAG);
if (mWrite) {
// We want to write
mWrite = false;
// TODO: write to tag
} else {
// not in write-mode
// TODO: read tag or do nothing
}
}
}
Regarding the second part of your question, when you want to receive NFC tag discovery events while your activity is already in the foreground, you should register with the NFC foreground dispatch system. See Advanced NFC: Using the NFC Foreground Dispatch System. There is no need to destroy and re-create your activity.

Launching app from home screen will launch it on top of an existing instance if it was launched previously from the app screen, vise versa

There seems to be a bug of some sort with the play store installer, whenever I try to resume my app from the home screen icon rather than the app screen it will launch again on top of my already running app. This is true for the other way around
I've tried this code
if (!isTaskRoot()) {
final Intent intent = getIntent();
final String intentAction = intent.getAction();
if (intent.hasCategory(Intent.CATEGORY_LAUNCHER)
&& intentAction != null
&& intentAction.equals(Intent.ACTION_MAIN)) {
finish();
}
}
But all it does it crash the app if it tries launching in the fashion I stated.
My manifest is also set to
android:launchMode="singleTask"
I found that if I take exactly the same APK and install it using "adb install", my app works correctly and as I expect.
However, if I (or my users) download the apk and install it from the Downloads, I find the behaviour described above, namely a new instance of my Activity being created on the stack when the user navigates to home and then back to the app via the launcher. This can be verified with "adb shell dumpsys activity "
I fixed the issue by using the following at my Launch Activity
ublic class StartupActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (needStartApp()) {
Intent i = new Intent(StartupActivity.this, GameActivity.class);
startActivity(i);
}
finish();
}
#Override
public void onConfigurationChanged(Configuration newConfig) {
// this prevents StartupActivity recreation on Configuration changes
// (device orientation changes or hardware keyboard open/close).
// just do nothing on these changes:
super.onConfigurationChanged(null);
}
private boolean needStartApp() {
final ActivityManager am = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
final List<RunningTaskInfo> tasksInfo = am.getRunningTasks(1024);
if (!tasksInfo.isEmpty()) {
final String ourAppPackageName = getPackageName();
RunningTaskInfo taskInfo;
final int size = tasksInfo.size();
for (int i = 0; i < size; i++) {
taskInfo = tasksInfo.get(i);
if (ourAppPackageName.equals(taskInfo.baseActivity.getPackageName())) {
// continue application start only if there is the only Activity in the task
// (BTW in this case this is the StartupActivity)
return taskInfo.numActivities == 1;
}
}
}
return true;
}
}

PlayHaven Android integration

I'm trying to implement PlayHaven's SDK in my Android application and while I do get Interstital ads, I cannot seem to capture the event of content dismissed.
I do get a log when the content is loaded.
This is what I've tried:
PlayHaven.configure(this, R.string.token, R.string.secret);
OpenRequest open = new OpenRequest();
open.send(this);
placement = new Placement("some_placement");
placement.setListener(pl); //PlacementListener
placement.preload(this);
The PlacementListener(pl) implementation:
private PlacementListener pl = new PlacementListener() {
#Override
public void contentLoaded(Placement placement) {
Log.i(TAG_PH, "PlayHaven contentLoaded");//this log is displayed
startActivity(FullScreen.createIntent(Splash.this,placement));
}
#Override
public void contentFailed(Placement placement, PlayHavenException e) {
Log.i(TAG_PH, "PlayHaven contentFailed");
}
#Override
public void contentDismissed(Placement placement, DismissType dismissType,
Bundle data) {
Log.i(TAG_PH, "PlayHaven content Dismissed");//this log is **NOT** displayed
}
};
In your onActivityResult method, you can use the following code:
String placementTag = data.getStringExtra(PlayHavenView.BUNDLE_PLACEMENT_TAG);
PlayHavenView.DismissType dismissType = (PlayHavenView.DismissType) data.getSerializableExtra(PlayHavenView.BUNDLE_DISMISS_TYPE);
You will get back dismissType. The values you are looking for are EmergencyClose (triggered when a user clicks on the X button to close a content unit), NoThanks (user declines the content unit offer), SelfClose (the Content Unit dismisses itself which happens when the SDK has to intelligently close a content unit), and BackButton (when the user presses back).

Categories

Resources