I would like to check a number of Spinner controls in the Onclick event of a few buttons (if the user moves away from the Activity), and if one or more were not filled out, display a warning message with 2 options to the user:
#Override
public void onClick(View v) {
int i1 = spinner1.getSelectedItemPosition();
(..)
if ((i1 == 0) | (i2 == 0) | (i3 == 0) | (i4 == 0) | (i5 == 0)) {
AlertDialog.Builder alertbox = new AlertDialog.Builder(this);
alertbox.setMessage("Answers missing, what do you want to do?");
final CharSequence[] items = {
"Oops.. let me fix that…",
"I want to leave the app now" };
alertbox.setTitle("Pick an item");
alertbox.setItems(items, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int item) {
if (item == 1) {
finish();
// should lead back to the spinner controls on the page
}else if (item == 2){
finish();
android.os.Process.killProcess(android.os.Process
.myPid());
}
}
}).create();
alertbox.show();
However, I just see an empty box with the title, but the message set with setMessage() is not displayed, and I don't get any list items for selection - the box is empty! Any idea what I can do to fix that?
I have been having the same issue, and I found that if I remove the .setMessage line, then the list appears with the title. Not sure why this is though. If you use the .setpositive button, .negative, etc, then you can have a message. I also noticed that google examples all don't use .setMessage with an item list. They only use .setTitle, which doesn't give you that much space.
So, while this doesn't help you if you want a long message, it will get your list visible if that is your main goal.
Related
I've created an AccessibilityService in Android where I want to display an AlertDialog after focusing on an EditText on the page (Note: The EditText could be from another app, like a login screen, so I won't always know the ID). When you click on a 'confirm' button within the AlertDialog it populates that EditText with text.
I have all of the steps complete except for the last part...I cannot figure out how to populate the EditText with text. I'm guessing there is a way to cast a findViewByID() method somewhere, but I don't know how to find the ID of the EditText (see above, the EditText could be from another app). See code below, am I way off? The code below always errors out telling me about a sealed instance problem (Cannot perform this action on a not sealed instance.).
public void onAccessibilityEvent(final AccessibilityEvent event) {
final AccessibilityNodeInfo source = event.getSource();
if ((event.getEventType() == AccessibilityEvent.TYPE_VIEW_CLICKED || event.getEventType() == AccessibilityEvent.TYPE_VIEW_FOCUSED) && CLASS_NAME_EDIT_TEXT.equals(event.getClassName())) {
AlertDialog.Builder mSuspendDialog = new AlertDialog.Builder(getApplicationContext())
.setTitle(R.string.str_have_password_question)
.setPositiveButton(R.string.str_decision_use_password, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
if (event.getSource() != null & event.getClassName().equals("android.widget.EditView")) {
Bundle arguments = new Bundle();
arguments.putCharSequence(AccessibilityNodeInfo
.ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE, "newtexttopopulateedittext");
event.getSource().performAction(AccessibilityNodeInfo.ACTION_SET_TEXT, arguments);
}
}
})
.setNegativeButton(R.string.str_decision_close, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
// User cancelled the dialog
}
});
AlertDialog alert11 = mSuspendDialog.create();
// Ensure we can show the dialog from this service.
alert11.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
alert11.show();
1) When any activity starts, create a List(or whatever) of ID's of all the EditText's on the screen.
2) While creating a list (or later on) iterate through the list again and check if a value is available for that view in your SQLite database.
3) If a value is available, use ACTION_PASTE to inject text in that EditText.
ArrayList<AccessibilityNodeInfo> inputViewsList = new ArrayList<AccessibilityNodeInfo>();
AccessibilityNodeInfo rootNode = getRootInActiveWindow();
refreshChildViewsList(rootNode);
for(AccessibilityNodeInfo mNode : inputViewsList){
String viewId = mNode.getViewIdResourceName();
Cursor cr = db.rawQuery(-----your database parameters----);
if(cr.moveToFirst()){
//this means you have a value for that ET
ClipboardManager clipboardManager = (ClipboardManager)getSystemService(CLIPBOARD_SERVICE);
ClipData clipData =ClipData.newPlainText("MyAppName", cr.getString(--Your column number--));
clipboardManager.setPrimaryClip(clipData);
mNode.performAction(AccessibilityNodeInfo.ACTION_PASTE);
}
}
Database has to be used so that you can remember the values permanently. The ID which i'm getting above is a fully qualified ID with App package name and view ID. So, it remains unique system-wide.
Now about refreshChildViews() method:
private void refreshChildViews(AccessibilityNodeInfo rootNode){
int childCount = rootNode.getChildCount();
for(int i=0; i<childCount ; i++){
AccessibilityNodeInfo tmpNode = rootNode.getChildAt(i);
int subChildCount = tmpNode.getChildCount();
if(subChildCount==0){
if(tmpNode.getClassName().toString().contentEquals("android.widget.EditText"){
inputViewsList.add(tmpNode);
}
return;
}
if(subChildCount>0){
refreshChildViews(tmpNode);
}
}
}
Don't forget to clear the inputViewsList on TYPE_WINDOW_STATE_CHANGED event!
Let me know if you need anything else.
I have a small random number spinner that when you click gives a random number. I am having two problems. The first is when the main activity loads it displays a random number on the screen without the random number spinner being clicked. I am unsure what to set to false to keep it from opening with the main activity. The second problem is that when you select an option from the spinner it does not clear. Meaning that If you click on option D6 or D20 then you can not click on the same option again until selecting the other option first. Essentially the selection does not clear out of memory after the random number is selected. Here is the random number code
public void onItemSelected(AdapterView<?> parent, View view, int pos,
long id) {
Random rand = new Random();
int roll = 0;
boolean firstRun = false;
// An item was selected.
if (!firstRun)
{
if (spinner1.getSelectedItemPosition()==0)
{
roll = rand.nextInt(6)+1;
}
else
{
roll = rand.nextInt(20)+1;
}
}
else
{ firstRun = false; }
// Put the result into a string.
String text = "You rolled a " + roll;
// Build a dialog box and with the result string and a single button
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setMessage(text).setCancelable(false)
.setPositiveButton("OK", new
DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id)
{
// do things when the user clicks ok.
}
});
AlertDialog alert = builder.create();
// Show the dialog box.
alert.show();
}
...when the main activity loads it displays a random number on the screen without the random number spinner being clicked.
This is because onItemSelected() is called when the Activity is first created. To avoid running this code simply create a member variable (declared outside of a method, preferably before onCreate() for readability) like a boolean. And check that. For example
public void onItemSelected(AdapterView<?> parent, View view, int pos,
long id)
{
if (!firstRun) // where firstRun is the boolean variable you create
// and set to true
{
// run your code
}
else
{ firstRun = false; }
}
The second problem is that when you select an option from the spinner it does not clear.
I'm not exactly sure what you mean by this but you could set an empty value ("") for your first position then after each call to onItemSelected() call setSelection(0)
I've created an array of 5 clickable textviews using a loop, have set their parameters (size, colour, background image, to be clickable etc) and have set an onClickListener and the array is called "myArrayofTVs". Their ids have been set using the loop int (i). I have another predefined array that hold text string, and other textviews are present on the layout. Later on in the onClick method, and as all the buttons/clickable textviews do something very similar, I'd like to be able to do something like:
#Override
public void onClick(View v) {
if(v == myArrayofTVs[i]) { //using 'i' here doesn't seem to work
tv1.setText(myArray2[i]);
tv2.setText(myArray2[i+1];}
etc
etc}
I've tried various differnt ways such as using switch case statements (don't really want to use these as there will be a lot of repeated code and I'll have to add a new case statement each time I want to add new textview/buttons in the future). Is there anyway of using one statement that will handle all the buttons/clickable textviews based on the variable id given or will I have to use a separate case/tag/id statement for each one?
Many thanks in advance!
Add the views to your ViewGroup and use getChildAt(int index) and getChildCount() to create a loop. You can loop all children/views in the viewgroup and you could check with
if(child instanceof TextView)
if they are of the correct type. Then you could cast the views back to a TextView/Button/View and do the thing you want to do.
But it sounds like you want a list of something. So i would suggest using a ListView with a adapter behind it.
I really think you should use the id provided by Android instead of trying to compare objects. The reason your code wouldn't work, if it had a sufficient for loop around it, is somewhat mysterious, but I would try to parallel the switch statements you see in examples as much as possible by comparing ID's and not objects.
for( int i = 0; i < myArrayofTvs.length; i++ )
if(v.getId() == myArrayofTVs[i].getId()) {
tv1.setText(myArray2[i]);
tv2.setText(myArray2[i+1];
}
}
Also obviously you'll want to avoid an array out of bounds error in that second inner statement.
What I did was programmatically inflate my custom layout and used an onClickListener on that button from the custom layout inflated. Then to interact with a specific item I got the parent view of the view being clicked eg. your button and then used that view to change attributes of the view. This is a snippet of my code. The onClick of the alertDialog is where I go about changing values of the newly inflated view.
// if an edit button of numbers row is clicked that number will be edited
if (view.getId() == R.id.NumberRowEditButton)
{
AlertDialog.Builder alert = new AlertDialog.Builder(this);
alert.setTitle("Contact edit");
alert.setMessage("Edit Number");
// Set an EditText view to get user input
final EditText input = new EditText(this);
input.setSingleLine();
alert.setView(input);
alert.setPositiveButton("Ok", new DialogInterface.OnClickListener()
{
public void onClick(DialogInterface dialog, int whichButton)
{
// get input
Editable value = input.getText();
if(value.length() > 4){
View tempView = (View) view.getParent();
TextView tempTV = (TextView) tempView.findViewById(R.id.numberRowTextView);
String number = tempTV.getText().toString();
tempTV.setText(value.toString());
}
else
{
// ...warn user to make number longer
final Toast msgs = Toast.makeText(ContactEdit.this, "Number must be over 4 digits.", Toast.LENGTH_SHORT);
msgs.setGravity(Gravity.CENTER, msgs.getXOffset() / 2, msgs.getYOffset() / 2);
msgs.show();
}
}
});
alert.setNegativeButton("Cancel", new DialogInterface.OnClickListener()
{
public void onClick(DialogInterface dialog, int whichButton)
{
// cancel the dialog
dialog.cancel();
}
});
alert.show();
}
Hopefully this might help you.
I've spent over a week trying to figure out a way to do a Limited Multi Selection Preference list. Nothing I've tried works. I'm ready to give up on Android if something seemingly simple is so hard. I've been programming a long time and don't remember being beaten up this badly by something like this. I have to assume I am not understanding something basic. I hope someone can point me in the right direction.
Here is the simplest code I can think off that should work. It does not clear the checkbox even when setting it to false, I've tried true as well. Why doesn't that work? If that will not work, what will?
Any help would be most appreciated.
#Override
protected void onPrepareDialogBuilder(Builder builder)
{
CharSequence[] entries = getEntries();
CharSequence[] entryValues = getEntryValues();
if (entries == null || entryValues == null || entries.length != entryValues.length ) {
throw new IllegalStateException(
"ListPreference requires an entries array and an entryValues array which are both the same length");
}
// Added by WJT since we are loading the entries values after instantiation
// we need the clicked indexes to be setup now, they would not have been
// set up in the constructor
if ((mClickedDialogEntryIndices == null) || (mClickedDialogEntryIndices.length == 0))
mClickedDialogEntryIndices = new boolean[getEntries().length];
restoreCheckedEntries();
builder.setMultiChoiceItems(entries, mClickedDialogEntryIndices,
new DialogInterface.OnMultiChoiceClickListener()
{
public void onClick(DialogInterface dialog, int which, boolean val)
{
mDlg = (AlertDialog)getDialog();
mListView = (ListView)mDlg.getListView();
if (val)
{
if (mSelectedCount < mLimit)
{
mClickedDialogEntryIndices[which] = val;
mSelectedCount++;
}
else
{
mListView.setItemChecked(which, false);
Toast.makeText(getContext(),
R.string.newsLimitExceededMessage,
Toast.LENGTH_LONG).show();
} // (mSelectedCount < mLimit)
}
else
{
mClickedDialogEntryIndices[which] = val;
mSelectedCount--;
} // (val)
} // void onClick(DialogInterface dialog, int which, boolean val)
}); // DialogInterface.OnMultiChoiceClickListener()
} // void onPrepareDialogBuilder(Builder builder)
Thanks,
\ ^ / i l l
Here's how I would approach the problem:
Step #1: Get this working in a standalone throwaway test activity. Forget preferences. Forget dialogs. Just focus on the functionality of having a CHOICE_MODE_MULTIPLE ListView where, after a certain number of items are checked, the unchecked items become disabled.
Step #2: Get the functionality from Step #1 working in the form of a custom widget. By this, I mean you would implement a subclass of ListView (I guess...might be some container if there's more to it than a ListView) that bakes in all of what you need from Step #1.
Step #3: Create a custom DialogPreference subclass that uses the custom widget from Step #2.
For example, here is a sample project where I have a custom ColorMixer widget, rolled into a ColorPreference.
I am currently using the AlertDialog.builder to create a multichoice list for the user (checkboxes). This works great, except we want one of the buttons to deselect all of the others in the list.
builder.setMultiChoiceItems(list, checked,
new DialogInterface.OnMultiChoiceClickListener() {
public void onClick(DialogInterface dialog,
int item, boolean isChecked) {
if(item == ANY_ITEM_BUT_0)
{
((AlertDialog) dialog).getListView().setItemChecked(0, false);
}
}
});
When using "true" it will successfully check the box, but when using false it does not uncheck it (unless i have manually set it to true before hand.) Is there a separate listener I should be using to detect when a user clicks these? It seems to me that there are two checkmarks set, one by the "setItemChecked(0, true);", and one by actually selecting it.
This has been driving me nuts for a couple days now, any help would be greatly appreciated.
OH!!! I forget it to ensure deselect you must change checked to null ;), I had the same issue.
builder.setMultiChoiceItems(list, null, new DialogInterface.OnMultiChoiceClickListener() {
...
To deselect the other items it works fine::
if(item == ANY_ITEM_BUT_0){
for(int i=0; i<items.length;i++){
if (item != ANY_ITEM_BUT_0)
((AlertDialog)dialog).getListView().setItemChecked(i, false);
}
}
Dont think you can change the values in the list since the list-items (checkboxes) are controlled by the builder-object. However, you could simply make the dialog re-initiate when the first item is clicked... by dismissing the dialog that is showing, and create a new one....
If you want to set a check box to not be checked and you need to set the checkedItems array on the call to setMultiChoiceItems(), you need to set the checked array items to false as well. Make sure your checked array is final so you can access it in the listener.
builder.setMultiChoiceItems(list, checked,
new DialogInterface.OnMultiChoiceClickListener() {
public void onClick(DialogInterface dialog,
int item, boolean isChecked) {
if(isChecked && item == ANY_ITEM_BUT_0)
{
for(int i=0; i<list.length;i++){
if (i != ANY_ITEM_BUT_0) {
checked[i] = false;
((AlertDialog)dialog).getListView().setItemChecked(i, false);
}
}
}
}
});