You pass in the pool of letters to select from without distinguishing between letters and digits. If you want to ensure both are included, then you need to keep them separate for longer.
The TextView
parameter is a needless complication and belongs somewhere in the calling GUI code, rather than in this utility method. You can add it back in if you have to.
This version picks a letter if switchLetters
is checked and picks a digit if switchNumbers
is checked, ensuring at least one of each selected type is picked. The rest of the characters are random.
Because the first two characters are in a specific order, the result is securely shuffled. That is why I used an array to hold the result, so it was easier to shuffle.
I have put in a lot of comments to help explain things.
final String alpha = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
final String digits = "0123456789";
Random secRand = new SecureRandom();
String randomString(int len) {
if (len < 2) {
throw new IllegalArgumentException("randomString - length too short: " + len);
}
// Pool of characters to select from.
String pool = "";
// Array to hold random characters.
Character[] result = new Character[len];
// Index into result.
int index = 0;
if (switchLetters.isChecked()) {
// Put letters in pool.
pool = pool + alpha;
// Ensure at least one letter.
result[index] = alpha.charAt(secRand.nextInt(alpha.length()));
index++;
}
if (switchDigits.isChecked()) {
// Put digits in pool.
pool = pool + digits;
// Ensure at least one digit.
result[index] = digits.charAt(secRand.nextInt(digits.length()));
index++;
}
// Fill rest of result array from pool.
for ( ; index < len; index++) {
result[index] = pool.charAt(secRand.nextInt(pool.length()));
}
// Shuffle result array with secRand to hide ordering.
Collections.shuffle(Arrays.asList(result), secRand);
// Assemble return string.
StringBuilder sb = new StringBuilder(len);
for (Character c : result) {
sb.append(c);
}
return sb.toString();
} // end randomString()