Exception when focusing a EditText in a PopupWindow running on Device - java

I'm developing a PopUp window for Android, and it's working, I added a EditText and a Button on that, when running on ADV this work properly, while running on device, when I focus on the EditText this throws a weird Exception.
android.view.WindowManager$BadTokenException: Unable to add window - - token android.view.ViewRoot&48163b18 is not valid; is your active running?
I don't know if it matters, but I'm running on a Galaxy Tab with Swype input.
Now I read the specs of the Window.showAtLocation
public void showAtLocation (View parent, int gravity, int x, int y)
Display the content view in a popup window at the specified location. If the popup window cannot fit on screen, it will be clipped. [...]
Parameters
parent a parent view to get the getWindowToken() token from
[...]
The problem is just in that token, but how do I pass the Activity token to it?
I also wrote a small code to reproduce the error.
PopupWindow window = new PopupWindow(activity);
window.setWidth(WindowManager.LayoutParams.WRAP_CONTENT);
window.setHeight(WindowManager.LayoutParams.WRAP_CONTENT);
window.setTouchable(true);
window.setFocusable(true);
EditText text = new EditText(activity);
text.setText("Dont touch, this crash!");
window.setContentView(text);
window.showAtLocation(arg0, Gravity.NO_GRAVITY, 10,10);
Running on AVD all works fine, while on device this crash and throw the error I mentioned.
I discover something new, when I'm in landscape mode this errors don't occurs.

Thank you, TheRedPill!
I had the same problem with EditText inside PopupWindow behaving stragely. It worked on Samsung Galaxy S3, HTC One X but crashed on Huawei MediaPad FHD 10. As soon as I started editing the application crashed.
Your solution:
editText.setInputType(InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS);
Solved the issue for me.
The stack-trace was:
08-15 15:49:03.690: ERROR/AndroidRuntime(8692): FATAL EXCEPTION: main
android.view.WindowManager$BadTokenException: Unable to add window -- token android.view.ViewRootImpl$W#417eefa8 is not valid; is your activity running?
at android.view.ViewRootImpl.setView(ViewRootImpl.java:585)
at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:326)
at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:224)
at android.view.WindowManagerImpl$CompatModeWrapper.addView(WindowManagerImpl.java:149)
at android.view.Window$LocalWindowManager.addView(Window.java:547)
at android.widget.PopupWindow.invokePopup(PopupWindow.java:988)
at android.widget.PopupWindow.showAtLocation(PopupWindow.java:845)
at android.widget.PopupWindow.showAtLocation(PopupWindow.java:809)
at android.widget.Editor$PinnedPopupWindow.updatePosition(Editor.java:2147)
at android.widget.Editor$PinnedPopupWindow.show(Editor.java:2104)
at android.widget.Editor$SuggestionsPopupWindow.show(Editor.java:2349)
at android.widget.Editor.showSuggestions(Editor.java:1647)
at android.widget.Editor$1.run(Editor.java:1546)
at android.os.Handler.handleCallback(Handler.java:615)
at android.os.Handler.dispatchMessage(Handler.java:92)
at android.os.Looper.loop(Looper.java:137)
at android.app.ActivityThread.main(ActivityThread.java:4745)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:511)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:786)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:553)
at dalvik.system.NativeStart.main(Native Method)

The cause:
I trace the cause of the error down to the spelling auto-correct behavior on some phones (Moto Droid Razr and few other Moto Phones) and some android Rom (like some CM7 and CM7.1 ROMS). If the text contain a word that is incorrectly spell, and the text cursor is hovering in or near the text, the android OS will try automatically bring up the keyboard and try to provide suggestions on a correct spelling.
On most devices, the auto correct suggestion box only appear as a one line segment above the keyboard. However on some custom ROMs (CM7 being one I seem a lot happening to) and some devices (Droid Razr), there is an additional drop down selection box that appear :
See this image of what the auto-correct popup looks like (sorry not enough rep to insert image)
I highly suspect that the auto correct drop-down list is also implemented as a popup window, and it is trying to use the current popup (the one containing the EditText with the mis-spell word) as the root view, and trying to get the windowToken from the root view.
Since the popup itself is not a traditional view, I am assuming it is unable to give the correct windowToken to other views who are asking for them, therefore leading to the error.
The Solutions:
1) The easiest way I been able to get around this problem is by using Dialog instead of Popup windows. Their API is really similar and in my cases are fairly easy to replace PopupWindow using Dialog.
For example:
Old code:
LayoutInflater inflater = (LayoutInflater) parentActivity.getLayoutInflater();
View mainView = parentActivity.findViewById(R.id.main_calendar_fragment);
updateEventPopupWindow = new PopupWindow(inflater.inflate(
R.layout.add_event_fragment, null, false), metrics.widthPixels, metrics.heightPixels, true);
updateEventPopupWindow.setBackgroundDrawable(new BitmapDrawable());
updateEventPopupWindow.showAtLocation(mainView, Gravity.CENTER, 0, 0);
New code:
LayoutInflater inflater = (LayoutInflater) parentActivity.getLayoutInflater();
View mainView = parentActivity.findViewById(R.id.main_calendar_fragment);
updateEventDialog = new Dialog(parentActivity, android.R.style.Theme_NoTitleBar);
updateEventDialog.setContentView(inflater.inflate(R.layout.add_event_fragment, (ViewGroup) mainView, false));
updateEventDialog.show();
2) The second approach is harder, but might be a suitable if PopupWindow to Dialog replacement is not doable, is to user Fragments in place of PopupWindows. There are many good fragment tutorials out there, so I won't bother to go over how to do this in this post.
3) As a last resort, like multiple posters mentioned above, you can turn-off text auto correct on the EditText fields inside the PopupWindwow to side step this problem. However this lead to horrible user experiences, since many users (and keyboards like swype) relies on auto-correct, doing this will likely drive user away from your application.
Hope this helps other out there who are facing this problem. I banged my head against the keyboard for over a day before finally decided to try the Dialog approach, which to my surprise was fairly easy to swap out. Best of luck to you

I tried to run your code but everything works fine for me... Here is the test class I wrote :
public class TestActivity extends Activity
{
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Button btn = (Button) findViewById(R.id.testBtn);
btn.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v)
{
showPopup();
}
});
}
private void showPopup()
{
PopupWindow window = new PopupWindow(this);
window.setWidth(WindowManager.LayoutParams.WRAP_CONTENT);
window.setHeight(WindowManager.LayoutParams.WRAP_CONTENT);
window.setTouchable(true);
window.setFocusable(true);
EditText text = new EditText(this);
text.setText("Touch it, it doesn't crash");
window.setContentView(text);
window.showAtLocation(text, Gravity.NO_GRAVITY, 30, 30);
}
}
main.xml :
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<Button
android:id="#+id/testBtn"
android:text="Popup"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
Maybe you tried to run the popup code in the onCreate() function? If I do it, it throws the same Exception as yours, but it's normal since when onCreate() is called the activity is not fully initialized yet.
(I tried on a Galaxy Tab too, but without swype input)

EditText text = new EditText(activity);
text.setText("Dont touch, this crash!");
this actually is the cause of exception..
when we bind the EditText to some text it falls out on click when virtual keyboard appears..
But the same code works fine when we do not bind the EditText
EditText text = new EditText(activity);
Although I am facing the same error, and not able to sort out till now....
Just putting efforts here to focus on problem creater line...
Can any body suggest why itz behaving such and how to fix this issue..
Thankx

I also got the same error when the edittext in my popupwindow had some text already present and the text wasn't a dictionary word (for e.g. a city name). When I click in between the text and boom! I got the exception.
I solved it by making the edittext not show auto correct suggestions:
android:inputType="textNoSuggestions"

Edited
try like this create a new class say Popupcls
public class PopUpFlag {
private PopupWindow pw;
public void initiatePopupWindow(Activity ctx) {
LayoutInflater inflater = (LayoutInflater) ctx.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View layout = inflater.inflate(R.layout.popupprofile, (ViewGroup) ctx.findViewById(R.id.popup_element));
EditText ettext = (EditText) layout.findViewById(R.id.edit);
pw = new PopupWindow(layout, 300, 400, true);
pw.showAtLocation(layout, Gravity.BOTTOM, 0, 0);
}
Now in your activity if you need popup when popup button click write like this
popupbtn.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
PopUpFlag puf=new PopUpFlag();
puf.initiatePopupWindow(YourActivityName.this);
}
});
I hope this helps

The crash occurs on an EditText placed in the WindowManager when user taps on a word underlined as red. Such a underlined word means that it does not exist in the dictionary. On the tap, OS tries to show up a pop with closest matching words from the dictionary and crashes since such a pop up can't be attached to the window due to bad token exception.
Only the following solution seemed to work for me programmatically
//assume an EditText object with name myEditText
myEditText.setInputType(myEditText.getInputType() | InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD | InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS);
InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS does not seem to work as expected on all keyboards whereas InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD has the drawback that it also disables toggling the language in the keyboard and the swipe gesture to add the text.

Related

How to switch back from one layout to the parent layout in the same activity

I'm creating a quiz app. Users are shown clues and have to guess the answer.
I have an activity with two layouts nested inside the "parent" constraint layout. The reason for this is that I needed a custom layout so I could pull rows from three columns from an SQLite database and display them in the app. These are the clues.
The top part of the activity is therefore this layout and the bottom part of the activity is another constraint layout that contains the buttons (refresh button to refresh the clues and check answer button) and the text view allowing the user to enter their text.
When I enter my activity, everything works fine. Clues are displayed and all buttons work.
When I press the refresh button (to refresh the clues), it refresh's the clue and then stops the buttons in the bottom layout from working, i.e I press them but nothing happens. My theory is that when I run the method that, it switches everything to the top layout and that stays (disabling the buttons in the bottom layout).
The bit of code that refresh's the clues, and therefore is causing the issue is this:
public void getPlayerHistory() { // Method used to get player history from DatabaseAccess.java,
// assign to list and place in the ListView
setContentView(R.layout.view_player_history); //the main layout everything is being displayed in
DatabaseAccess databaseAccess = DatabaseAccess.getInstance(getApplicationContext());
databaseAccess.open();
userList = new ArrayList<>();
Cursor data = databaseAccess.getListContents();
int numRows = data.getCount();
while (data.moveToNext()){
user = new User(data.getString(0), data.getString(1),
data.getString(2));
userList.add(user);
}
databaseAccess.close();
com.example.transfergame.ThreeClass adapter =
new com.example.transfergame.ThreeClass(this, R.layout.list_adapter_view, userList);
listView = (ListView) findViewById(R.id.listView);
listView.setAdapter(adapter);
Log.i("get player history", "playerHistoryFunction Run");
}
I think the issue is coming from this line
com.example.transfergame.ThreeClass adapter =
new com.example.transfergame.ThreeClass(this, R.layout.list_adapter_view, userList);
where I switch to my custom layout, but I'm not exactly sure what to code to then switch back to my parent layout.
Can someone point me in the right direction?
The issue actually came from
public void getPlayerHistory() {
setContentView(R.layout.view_player_history);
For some reason, setting this within this method, and not the onCreate() method was causing the issue. I have taken this out and put it in the onCreate() method and now everything runs fine.

Why my text is getting greyed-out? Probably Context has to do with something

So the Negative and Positive buttons of my AlertDialog are greyed-out, but they shouldn't be.
greyed-out text screen
I suspect it has something to do with Context, becouse once i had identical problem with my ListView. I have repaired that by changing argument in ArrayAdapter's reference from getApplicationContext() to getBaseContext(). Can someone explain it to me? I don't really understand the 'Context'
This is my code
AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this);
builder.setTitle("What do you want to do with " + getArrayList("ListOfRecipes").get(position) );
builder.setPositiveButton("Delete", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
List<String> list = new ArrayList<>(getArrayList("ListOfRecipes"));
Toast.makeText(getBaseContext(), list.get(position) + "has been removed", Toast.LENGTH_SHORT).show();
list.remove(position);
saveList(list, "ListOfRecipes");
}
});
builder.setNegativeButton("Modify", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
List<String> list = new ArrayList<>(getArrayList("ListOfRecipes"));
SharedPreferences sp = getSharedPreferences("Recip", MODE_PRIVATE);
SharedPreferences.Editor editor = sp.edit();
editor.putString("Recip", list.get(position));
editor.apply();
startActivity(new Intent(getBaseContext(), ManageRecipeActivity.class));
}
});
AlertDialog alertDialog = builder.create();
alertDialog.show();
First of all, if that piece of code is inside an activity, you can simply declare context with "this" (which is what you have done by passing MainActivity.this) to the dialog builder.
What I'm suspecting is that it may be that your MainActivity is getting a theme for the AlertDialog that is making the buttons look gray. You could check that out in your styles.xml (if there is a style defined for the dialog) and in the AndroidManifest file for the theme you are passing to your MainActivity.
If you don't find anything wrong/don't want to change the theme, I can think of two ways to solve that problem.
First way - Changing the button color (less work, but less flexible)
The first is actually changing the dialog button color as it's done in this post to whatever color you want.
Second way - inflating a custom view that meets your needs (more work, but more flexible)
The second way would be to inflate a view and pass it to the dialog. Actually, you don't really have to use the standard dialog style at all, you can inflate your own view inside it to fit your needs.
To do that, you must:
1) Inflate a chosen view
As an example:
LayoutInflater factory = LayoutInflater.from(this);
final View view = factory.inflate(R.layout.image_dialog_layout, null);
2) Pass the inflated view to your dialog builder:
final AlertDialog dialog = new AlertDialog.Builder(this);
dialog.setView(view);
//Additional code to set click listeners, i.e.
dialog.create().show();
}
That way, you'll be inflating whatever layout you want, so you can just put the buttons you want inside it (with the color, size, font type you want).
It is important to notice that, even after inflating a view to it, you can still use methods setPositiveButton and setNegativeButton, they will appear below your inflated layout in the dialog. So, beware inflating buttons AND using those methods, because the buttons will appear duplicated.
Since, in this case, you don't want them to be gray, you want to put buttons inside your layout, with whatever style you want, and inflate them (and reference them in your code through findViewById).
The biggest advantage of the second way is that you can inflate whatever you want, with the styles you want. You can even put images inside it, if you wish.
Hope it helps, let me know if it worked for you.
Context is an interesting topic in android. And one thing to understand is Application Context and Activity Context are different. You should make sure that any thing that is related to UI, you should be using Activity Context.
This can be things like
Showing a dialog
Starting another activity
Inflating a new layout
This is because Activity is the only Context on which the themes defined in your manifest are actually attached.
I also recommend Context, What Context article to get a complete picture.
Happy Coding :)

Is that logical and a right way to add a button to close application in java?

I'm using Android Studio.
In the MainActivity inside the onCreate I did:
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
startTime = SystemClock.uptimeMillis();
serverChecksThread.start();
status1 = (TextView) findViewById(R.id.textView3);
timerValue = (TextView) findViewById(R.id.timerValue);
uploadedfilescount = (TextView) findViewById(R.id.numberofuploadedFiles);
uploadedfilescount.setText("Uploaded Files: 0");
addListenerOnButton();
initTTS();
Button btn1 = (Button) findViewById(R.id.btn1);
btn1.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
finish();
System.exit(0);
}
});
}
And in the activity_main.xml I added:
<Button android:layout_width="fill_parent"
android:layout_height="wrap_content" android:id="#+id/btn1"
android:text="Close App" />
I have two questions.
The main is that if it's logical and good thing to do to add a button that will close the application so it will not leave anything behind? This way when i'm running the application over again on my android device it's starting clean reseted.
The sub question is when I click the button and exit the app then when I'm running it again for a millisecond the app blink. And it happen after I added this button code it wasn't before. I'm not getting error or exception but it's blinking for a very short time.
"Running" and "closed" are fuzzy concepts in Android. When an app is in the background, it may or may not actually be running. When an activity is in the backstack, an in-memory instance of it may or may not exist. When your last activity finishes, the framework may or may not kill the process. And when you start the app again, the framework may or may not create a new instance of your Application class.
Calling System.exit(0) is a bad idea because it short-circuits the Android framework. It may result in unspecified behavior (read: really strange bugs.) Better to just finish your last activity and let the framework do as it likes.
Whether it's good UX to show a close button is a matter of opinion. Google recommends against it. The preferred way to "close" an activity is by pressing the back button.
It is not necessary that you add a close button to an application on android because, there is usually a, either software button, or b, a hardware button on the device to close (minimize) applications. so it wouldn't be a good thing to add a button, and it would also be illogical
And for your second question, I did not quite understand your point.
Even if you close your app with a button, it won't be closed permanently, it still will be shown on the users device as a 'running on background app'. Because android is not working like windows, so its not so useful to add such a button.
As far as i know the only apps that using this button is using it to be sure in 100% that the user left the app and that the connection that he had will be closed, so no one else will be able to use his login or password...

How to handle exception while clicking link using textview in android

I am working on an android project in which i have to add links i am following the given below example.. But when i am clicking on the link neither it is highlighting nor i am able to access the link. Clicking on the link is causing an exception which says
android.util.AndroidRuntimeException: Calling startActivity() from outside of an Activity context requires the FLAG_ACTIVITY_NEW_TASK flag. Is this really what you want?
I want to open the link in the browser when i am clicking on the link.How to do it efficiently?. I am expecting an answer soon !Thank you
NB: i am using a dynamic textview in my actual project
public class StackOverflowActivity extends Activity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
TextView link = new TextView(getApplicationContext);
String linkText = "Visit the <a href='http://stackoverflow.com'>StackOverflow</a> web page.";
link.setText(Html.fromHtml(linkText));
link.setMovementMethod(LinkMovementMethod.getInstance());
}
Use android:autoLink="web" in your TextView xml. And if it does not work, try android:linksClickable="true"
Based on your error, if using dynamic TextView make sure you refer your view with this object as
TextView yourView = new TextView(this);
this refers to your Activity context where I think you might have made a little mistake.
You should not use getApplicationContext for creating a view with Activity context.
I believe you have to inflate the layout that contains your TextView before you can use it, like so:
getActivity().getLayoutInflater()

Robotium - Trying to click home button in app

I'm new to robotium and i'm trying to write a quick and dirty script to run through all screens in an app.
The problem i have mainly with the 'home button' in the app. I've tried lots of options but i cant seem to get it to click there except with index, which is not what i want.
When i check out the button with the hierarchyviewer it looks like this:
Link
However when i try for example:
assertTrue(
"Wait for text (id: myapp.R.id.home) failed.",
solo.waitForImageById("myapp.R.id.home", 20000));
solo.clickOnImage((ImageView) solo.findViewById("myapp.R.id.home"));
solo.waitForActivity("MenuActivity");
It fails at the waitForImageByID line. Ive tried multiple options like waitForImageButton etc, but i just cant seem to get it clicked. What am i missing here?
junit.framework.AssertionFailedError: View with id: '0' is not found!
at com.jayway.android.robotium.solo.Solo.getView(Solo.java:1990)
at com.jayway.android.robotium.solo.Solo.getView(Solo.java:1970)
at com.bitbar.recorder.extensions.OtherUtils.a(OtherUtils.java:246)
at com.bitbar.recorder.extensions.OtherUtils.b(OtherUtils.java:241)
at com.bitbar.recorder.extensions.v.a(Waiter.java:71)
at com.bitbar.recorder.extensions.ExtSolo.waitForImageButtonById(ExtSolo.java:4176)
at com.example.android.apis.test.Test.testRecorded(Test.java:137)
at java.lang.reflect.Method.invokeNative(Native Method)
at android.test.InstrumentationTestCase.runMethod(InstrumentationTestCase.java:214)
at android.test.InstrumentationTestCase.runTest(InstrumentationTestCase.java:199)
at android.test.AndroidTestRunner.runTest(AndroidTestRunner.java:191)
at android.test.AndroidTestRunner.runTest(AndroidTestRunner.java:176)
at android.test.InstrumentationTestRunner.onStart(InstrumentationTestRunner.java:554)
at android.app.Instrumentation$InstrumentationThread.run(Instrumentation.java:1740)
Use the following line to press the home button in the action bar
solo.clickOnActionBarHomeButton();
The issue is that the id that it is referring is not in your application, it is in androids default R file, try android.R.id.home and it should work fine. It is worth noting though that if your application uses action bar sherlock to support the action bar pre 4.0 that this will have a different ID there and you will have to handle this in your test.
You can see this for yourself looking at: http://developer.android.com/reference/android/R.id.html
When you are using ActionBarSherlock there are two different Ids you have to check, android.R.id.home for API-Level>11 and abs__home for lower levels (provided by ActionBarSherlock):
View homeButton = activity.findViewById(android.R.id.home);
if (homeButton == null) {
homeButton = activity.findViewById(R.id.abs__home);
}
What about this code:
ArrayList<LinearLayout> ll = solo.getCurrentViews(LinearLayout.class);
//You can change 1 with the ordinal number of LinearLayout you want to click.
solo.clickOnView(ll.get(1));
or also
ArrayList<ImageView> iv = solo.getCurrentViews(ImageView.class);
//You can change 0 with the ordinal number of Image you want to click.
solo.clickOnView(iv.get(0));
I think if you identify the correct id for view or linear layout or image view it should work.
Dave C's answer was working only partially for me. The button was clicked but before the preceding screen was loaded assertions had started and thus were always false. The solution is to run "home click" on the main thread (Robotium 5.2.1):
getInstrumentation().runOnMainSync(new Runnable() {
#Override
public void run() {
solo.clickOnActionBarHomeButton();
}
});
From your question I can see that it is an image view. You can click on any view using the following piece of code.
View view = solo.getView("View_name_from_hierachy_viewer");
solo.clickOnView(view);
View_name_from_hierachy_viewer in your case will be "home".
Let me know if this does not work.

Categories