How to create Fingerprint Lock using switch to enable/disable the Lock - android

I want to integrate fingerprint lock into my application. The user has a choice to enable/disable the lock using switch. How can I achieve it programmatically.
For Example something like this:
Choice to enable/disable the lock inside the application
When user opens the application

So I have implemented this type of feature in my app but I don't know whether its a viable feature you may find an easy and sensible method but this is what I do
I use shared preferences for this so first in the activity where https://i.stack.imgur.com/3FY78.jpg exist I do like below
First I create this method
private void Biometric(){
androidx.biometric.BiometricManager biometricManager = androidx.biometric.BiometricManager.from(this);
switch (biometricManager.canAuthenticate(BiometricManager.Authenticators.BIOMETRIC_WEAK | BiometricManager.Authenticators.DEVICE_CREDENTIAL)) {
// this means we can use biometric sensor
case androidx.biometric.BiometricManager.BIOMETRIC_SUCCESS:
SharedPreferences sharedPreferences = getSharedPreferences("Authentication",0);
SharedPreferences.Editor editor = sharedPreferences.edit();
editor.putString(TEXT, "1");
editor.putBoolean(SWITCH1, Swicth_authenticate.isChecked());
editor.apply();
Intent intent = new Intent(AboutActivity.this, edit_profile.class);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(intent);
finish();
break;
// this means that the device doesn't have fingerprint sensor
case androidx.biometric.BiometricManager.BIOMETRIC_ERROR_NO_HARDWARE:
Swicth_authenticate.setChecked(false);
Toast.makeText(this, "Error code 0x08080101 Authentication failed there's no Fingerprint Reader in your device.", Toast.LENGTH_SHORT).show();
break;
// this means that biometric sensor is not available
case androidx.biometric.BiometricManager.BIOMETRIC_ERROR_HW_UNAVAILABLE:
Swicth_authenticate.setChecked(false);
Toast.makeText(this, "Error code 0x08080102 Authentication failed biometric system not found.", Toast.LENGTH_SHORT).show();
break;
// this means that the device doesn't contain your fingerprint
case BiometricManager.BIOMETRIC_ERROR_NONE_ENROLLED:
Swicth_authenticate.setChecked(false);
Toast.makeText(this, "Error code 0x08080103 There's no password for this device.", Toast.LENGTH_SHORT).show();
break;
case BiometricManager.BIOMETRIC_ERROR_SECURITY_UPDATE_REQUIRED:
break;
case BiometricManager.BIOMETRIC_ERROR_UNSUPPORTED:
break;
case BiometricManager.BIOMETRIC_STATUS_UNKNOWN:
break;
}
}
And Activate the above method whenever a user turns on the checkbox
And if user Deactivates I run the following in a method
SharedPreferences sharedPreferences = getSharedPreferences("Authentication",0);
SharedPreferences.Editor editor = sharedPreferences.edit();
editor.putString(TEXT, "0");
editor.putBoolean(SWITCH1, Swicth_authenticate.isChecked());
editor.apply();
As you can see I have used Shared Preferences in that method and in my launcher activity I do the following thing.
SharedPreferences sharedPreferences = getSharedPreferences("Authentication", 0);
String bio = sharedPreferences.getString(TEXT, "");
if (bio.equals("1")) {
BiometricManager biometricManager = androidx.biometric.BiometricManager.from(this);
switch (biometricManager.canAuthenticate(BiometricManager.Authenticators.BIOMETRIC_WEAK | DEVICE_CREDENTIAL)) {
// this means we can use biometric sensor
case BiometricManager.BIOMETRIC_SUCCESS:
break;
// this means that the device doesn't have fingerprint sensor
case BiometricManager.BIOMETRIC_ERROR_NO_HARDWARE:
break;
// this means that biometric sensor is not available
case BiometricManager.BIOMETRIC_ERROR_HW_UNAVAILABLE:
break;
// this means that the device doesn't contain your fingerprint
case BiometricManager.BIOMETRIC_ERROR_NONE_ENROLLED:
break;
case BiometricManager.BIOMETRIC_ERROR_SECURITY_UPDATE_REQUIRED:
break;
case BiometricManager.BIOMETRIC_ERROR_UNSUPPORTED:
break;
case BiometricManager.BIOMETRIC_STATUS_UNKNOWN:
break;
}
// creating a variable for our Executor
Executor executor = ContextCompat.getMainExecutor(this);
// this will give us result of AUTHENTICATION
final BiometricPrompt biometricPrompt = new BiometricPrompt(StartActivity.this, executor, new BiometricPrompt.AuthenticationCallback() {
#Override
public void onAuthenticationError(int errorCode, #NonNull CharSequence errString) {
super.onAuthenticationError(errorCode, errString);
}
// THIS METHOD IS CALLED WHEN AUTHENTICATION IS SUCCESS
#Override
public void onAuthenticationSucceeded(#NonNull BiometricPrompt.AuthenticationResult result) {
super.onAuthenticationSucceeded(result);
Toast.makeText(getApplicationContext(), "Login Success.", Toast.LENGTH_SHORT).show();
Intent intent = new Intent(StartActivity.this, MainActivity.class);
startActivity(intent);
finish();
}
#Override
public void onAuthenticationFailed() {
super.onAuthenticationFailed();
}
});
// creating a variable for our promptInfo
// BIOMETRIC DIALOG
final BiometricPrompt.PromptInfo promptInfo = new BiometricPrompt.PromptInfo.Builder().setTitle("Authentication")
.setDescription("Use your fingerprint to login ")
.setAllowedAuthenticators(BiometricManager.Authenticators.BIOMETRIC_WEAK | DEVICE_CREDENTIAL).build();
biometricPrompt.authenticate(promptInfo);
} else {
Intent intent = new Intent(StartActivity.this, MainActivity.class);
startActivity(intent);
finish();
}
If you have any doubt regarding this comment below I know its very huge but I don't know how much you know so I pretty much wrote whole code even then if you have doubt you can see the following source code https://github.com/MohammedAbidNafi/MessengerByMargs

Related

Save Login state, logical error with SharedPreferences and passing a Bundle

I am developing my first networking application and have a small problem which I am unable to find a solution for.
On my startscreen, which is my main activity, there is the option to login. If you login, my login class passes data per intent to my main activity so I can update my UI. This is my main acitivity :
// Just to make sure Loginstatus is false on first run
loginstatus = false;
//Get saved data from SharedPreferences
loginstatus = PreferenceData.getUserLoggedInStatus(this);
Log.d("Loginstatus",""+loginstatus);
if (extras != null) {
login = extras.getString("loginy");
idt = extras.getString("id");
name = extras.getString("name");
vorname = extras.getString("vorname");
email = extras.getString("login");
zsm = vorname + " " + name;
}
else {
// Take saved Data instead the Bundle Data form first Login
idt = PreferenceData.getUSERID(this);
name = PreferenceData.getNachname(this);
vorname = PreferenceData.getVorname(this);
email = PreferenceData.getLoggedInEmailUser(this);
}
Obviously extra is NULL on Startup. If login was successful, my login class passes Data and my main activity is called again, so extras is NOT NULL and I can update my UI with that information.In addition, I save my Data in SharedPrefernces if login was true.
The Problem is, I want to save my login state after completley closing my app. So i reopen my App and I want to use my SharedPrefernces data, but somehow extras is still NOT NULL and I cant find a way to fix that.
This is how I handle login. Hope this is helpfully.
Login Activity
Keep one shared preferences value to check login status which default value set to false;
#Override
protected void onResume() {
super.onResume();
if (sharedpreferences.getBoolean("firstRun", true)) {
initializeDatabase();
sharedpreferences.edit().putBoolean("firstRun", false).apply();
sharedpreferences.edit().putBoolean("attendance", false).apply();
sharedpreferences.edit().putBoolean("loginStatus", false).apply();
}
loginCheck();
}
inside loginCheck() check method redirect to menu activity based on login status.
public void loginCheck(){
if(sharedpreferences.getBoolean("loginStatus", true)){
Intent i = new Intent(this, MainMenuActivity.class);
startActivity(i);
this.finish();
}
}
In case of User haven't log previously, after authenticate user successfully add needed data in to shared preference and change login status shared preference value to true so above explained redirect will happen.
if (message.equals("Login successful")) {
String employeeId = responseBody.getString("employee_id");
int userId = responseBody.getInt("user_id");
String employeeName = responseBody.getString("employee_name");
SharedPreferencesReference.get().edit().putString("employee_id", employeeId).apply();
SharedPreferencesReference.get().edit().putInt("user_id", userId).apply();
SharedPreferencesReference.get().edit().putString("employee_name", employeeName).apply();
SharedPreferencesReference.get().edit().putBoolean("loginStatus", true).apply();
Toasty.success(ActivityWeakReference.get(), message, Toast.LENGTH_SHORT, true).show();
Intent i = new Intent(ActivityWeakReference.get(), MainMenuActivity.class);
ActivityWeakReference.get().startActivity(i);
ActivityWeakReference.get().finish();
}
Menu Activity
In menu activity you should have a logout button which allow users to logout by changing shared preference login status value. In My case I had it as a Menu Item.
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.logout:
sharedpreferences.edit().putBoolean("loginStatus", false).apply();
Intent intent = new Intent(this,MainActivity.class);
startActivity(intent);
break;
}
return true;
}

Android Firebase Phone Auth crashed when clicked button of empty edittext

With no problem, connected my app to firebase and I can test realtime database and other features, but when it comes to Phone Authentication, I am having problems. The problem is when Edittext is left empty and Button is clicked the app gets crashed. Don't know which code should be responsible for this problem.
Please help me to define it.
If you have carefully read the documentation of phone auth in firebase you will have below code:
private boolean validatePhoneNumber() {
String phoneNumber = mPhoneNumberField.getText().toString();
if (TextUtils.isEmpty(phoneNumber)) {
mPhoneNumberField.setError("Invalid phone number.");
return false;
}
return true;
Then either with if-else or switch-case
You should call this method
NOTE: onCLick method comes after btn.setOnClickListener depending upon your button id.
#Override
public void onClick(View view) {
switch (view.getId()) {
case R.id.button_start_verification:
if (!validatePhoneNumber()) {
return;
}
startPhoneNumberVerification(mPhoneNumberField.getText().toString());
break;
case R.id.button_verify_phone:
String code = mVerificationField.getText().toString();
if (TextUtils.isEmpty(code)) {
mVerificationField.setError("Cannot be empty.");
return;
}
verifyPhoneNumberWithCode(mVerificationId, code);
break;
case R.id.button_resend:
resendVerificationCode(mPhoneNumberField.getText().toString(), mResendToken);
break;
case R.id.sign_out_button:
signOut();
break;
}
}
Due to the codes which were not provided by you, I have written some references based on my own app. Please consider changing those and probably you wont get further crashes.

OnVideoChatChangeState() usage in Quickblox

I am using quickblox api for 1 to 1 videochat but I dont know the usage OnVideoChatChangeState() of OnQBVideoChatListener() class and with what changes the event is invoked. I have modified the code but the video doesnt start the click functions but doesn't go to:
` public void onVideoChatStateChange(CallState state, VideoChatConfig receivedVideoChatConfig) {
videoChatConfig = receivedVideoChatConfig;
isCanceledVideoCall = false;
Toast.makeText(getApplicationContext(), "switch", Toast.LENGTH_LONG).show();
switch (state)
{
case ON_CALLING:
Toast.makeText(getApplicationContext(), "After this the showCallDialog() will be called.", Toast.LENGTH_LONG).show();
showCallDialog();
break;
case ON_ACCEPT_BY_USER:
progressDialog.dismiss();
startVideoChatActivity();
break;
case ON_REJECTED_BY_USER:
progressDialog.dismiss();
break;
case ON_DID_NOT_ANSWERED:
progressDialog.dismiss();
break;
case ON_CANCELED_CALL:
isCanceledVideoCall = true;
videoChatConfig = null;
break;
case ON_START_CONNECTING:
progressDialog.dismiss();
startVideoChatActivity();
break;
default:
break;
}
}
};
`
and the showCallDialog(); method is not called this shows the events doesn't occur here.
So I want to know can the event occurs so that the methods are called.
This has been fixed. Master branch is updated. Please try download and use the sample once again.

OnCreate method keeps getting called repeatedly

Update: Thank you all for attempting to help me solve this bug. I am still unsure as to the cause, I was able to roll back to a previous commit and continue development from there. This previous commit did show the same bug, however after I commented out button.performClick() it went away. Strangely, this does not work on the most recent commit.
I still do not understand this bug and would appreciate any more assistance in helping determine the root cause. My greatest fear would be to inadvertently re-introduce it.
I have the most crazy error I have ever seen.
The OnCreate method is being called over and over again, freezing my application and giving me a slight flicker. The only solution is then to exit to the home screen and force quit the application from the settings menu.
Here is what is happening in detail:
Application starts (Main Activity)
Main Activity calls the Second Activity
Second Activity calls onCreate, sets up as normal
Second Activity randomly decides to exit onCreate <-- I think this what's happening
Second Activity's onCreate gets called again. It doesn't ever return to the Main Activity.
I have run a debugger, it appears that the second activity successfully completes the onComplete/onResume sequence, then decides to exit and restart.
Has anybody ever heard of this behavior before?
I haven't noticed any exceptions being thrown. Also, in the course of debugging, I did go ahead and check those locations that you see as silent fail. (this is the older code before I littered it with print statements)
UPDATE: When attempting to stop the process, I must turn on airplane mode. This means it has something to do with this code block (Second Activity)
else if (Network.haveNetworkConnection(Login.getContext()) && Login.checkClientId())
{...}
With no internet, it will hit the else statement and does not display this behavior.
CODE:
onResume() of the Main Activity, where I call the Second Activity:
#Override
public void onResume()
{
super.onResume();
//Check If logged in, else go to login page
Login.setContext(getApplicationContext());
//Reset Notification Number
GCMIntentService.cancelNotifications();
/** GO TO LOGIN **/
if(!Login.isLoggedIn())
{
//If user is not logged in, open login page
System.out.println("RESUMING MAIN AND STARTING LOGIN INTENT");
Intent intent = new Intent(ActivityMain.this, ActivityLogin.class);
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK|Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
} else
{
Login.setupStuffOnce();
Event.pullEvents(); //Get New Events
//Update ListView
updateMainFeed();
}
}
This is the Second Activity:
public class ActivityLogin extends Activity
{
private String postData;
//private Context c;
//final Timer timer = new Timer();
//Facebook Stuff
private Facebook facebook = new Facebook(Config.FBAPPID);
private AsyncFacebookRunner mAsyncRunner = new AsyncFacebookRunner(facebook);
//Layout Stuff
EditText username, password;
Button loginButton, signupButton;
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
// Open Database
Login.setContext(getApplicationContext());
Database.open(getApplicationContext());
}
/*
* #Override public void onPause() { s }
*/
#Override
public void onResume()
{
super.onResume();
// shouldn't put here but oh well
init();
//If coming from ActivitySignup
if(Transfer.username != null)
{
username.setText(Transfer.username);
password.setText(Transfer.password);
Transfer.password = null;
Transfer.username = null;
loginButton.performClick();
}
}
public void init()
{
Login.getUserLoggedIn();
if (Login.isLoggedIn())
{
//Do Any Additional Setup
Login.setupStuffOnce();
// If user is logged in, open main
Intent intent = new Intent(ActivityLogin.this, ActivityMain.class);
//intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
} else if (Network.haveNetworkConnection(Login.getContext()) && Login.checkClientId())
{
// Else, Make User Login
// Inflate Login and Present Website
String clientid = Login.getClientId();
System.out.println("clientid:" + clientid);
//System.exit(0);
postData = "mobile=1&client_id="+Login.getClientId();
// Inflate the view
setContentView(R.layout.activitylogin3);
username = (EditText) findViewById(R.id.username);
password = (EditText) findViewById(R.id.password);
//Inflate the Button
loginButton = (Button) findViewById(R.id.loginButton);
signupButton = (Button) findViewById(R.id.signupButton);
signupButton.setOnClickListener(new View.OnClickListener()
{
#Override
public void onClick(View v)
{
Intent intent = new Intent(ActivityLogin.this, ActivitySignup.class);
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP|Intent.FLAG_ACTIVITY_SINGLE_TOP);
startActivity(intent);
}
});
loginButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View view) {
int res = Login.sendLogin(username.getText().toString(), password.getText().toString());
if(res == 202)
{
//Login Successful
//Check if facebooked.
if(Login.isFacebooked())
{
//Just go to main
Intent intent = new Intent(ActivityLogin.this, ActivityMain.class);
//Are these flags necessary?
//intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
} else
{
//Go to facebook login page
//Intent intent = new Intent(ActivityLogin.this, ActivityFBLogin.class);
//startActivity(intent);
//Login via Facebook
doFacebook();
}
} else
{
System.out.println("Login Failed: "+res);
if(res == 405)
{
Toast.makeText(getApplicationContext(), "Incorrect Username/Password", Toast.LENGTH_SHORT).show();
password.setText("");
}
else
Toast.makeText(getApplicationContext(), "Network Error", Toast.LENGTH_SHORT).show(); //Not entirely true in all cases i think
}
/*Login.getUserLoggedIn();
if(Login.isLoggedIn())
{
Intent intent = new Intent(ActivityLogin.this, ActivityMain.class);
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
} else {
Toast.makeText(getApplicationContext(), "Please Login Above", Toast.LENGTH_SHORT).show();
}*/
}
});
} else
{
// Not Logged In and No Internet Access
setContentView(R.layout.activitylogintext);
EditText text = (EditText) findViewById(R.id.text);
text.setText("No Internet Connection Detected\n requires internet to login");
Button button = (Button) findViewById(R.id.refreshButton);
button.setOnClickListener(new View.OnClickListener() {
public void onClick(View view) {
//Login.getUserLoggedIn();
if(Network.haveNetworkConnection(Login.getContext()))
{
Intent intent = new Intent(ActivityLogin.this, ActivityLogin.class);
//intent.setFlags();
startActivity(intent);
} else {
Toast.makeText(getApplicationContext(), "No Internet Access Detected", Toast.LENGTH_SHORT).show();
}
}
});
}
}
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
facebook.authorizeCallback(requestCode, resultCode, data);
}
public void doFacebook()
{
facebook.authorize(this, Config.facebookPermissions, new DialogListener() {
#Override
public void onComplete(Bundle values) {
/*SharedPreferences.Editor editor = state.edit();
editor.putString("access_token", facebook.getAccessToken());
editor.putLong("access_expires", facebook.getAccessExpires());
editor.commit();
*/
//Input into database
Login.saveAccessToken(facebook.getAccessToken());
Login.setFB(facebook.getAccessToken());
//Login.sendAccessToken(facebook.getAccessToken());
//Intent into Main Activity
Intent intent = new Intent(ActivityLogin.this, ActivityMain.class);
//intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
}
#Override
public void onFacebookError(FacebookError error) {
Toast.makeText(getApplicationContext(), "Error: "+error.getErrorType(), Toast.LENGTH_SHORT).show();
}
#Override
public void onError(DialogError e) {
Toast.makeText(getApplicationContext(), "Error: "+e.getMessage(), Toast.LENGTH_SHORT).show();
}
#Override
public void onCancel() {}
});
}
public boolean checkForUserID(Context c)
{
try{
String res = Network.getUrl("www.website.com/mobile.php?got_user=1&client_id="+Login.getClientId());
JSONObject json = JSON.constructObject(res);
if(JSON.handleCode(json))
{
if(json.getString("type").equals("userid"))
{
Login.setLogin(json.getString("data"));
return true;
}
}
} catch(Exception e)
{
//Silent Fail
}
return false;
}
}
I believe that the problem will be resolved if you finish your MainActivity after you call SecondActivity. The problem probably is that the onResume event is immediatelly fired when you resume your MainActivity. That is because the MainActivity was probably destroyed and recreated while it was in background. Another solution would be to save your Activity's state with onSaveInstanceState. See here for more information.
Check this code in your activity:
Button button = (Button) findViewById(R.id.refreshButton);
button.setOnClickListener(new View.OnClickListener() {
public void onClick(View view) {
if(Network.haveNetworkConnection(Login.getContext()))
{
Intent intent = new Intent(ActivityLogin.this, ActivityLogin.class);
//intent.setFlags();
startActivity(intent);
} else {
Toast.makeText(getApplicationContext(), "No Internet Access Detected", Toast.LENGTH_SHORT).show();
}
}
});
Here you are calling ActivityLogin itself.
That's why the onCreate() is being called again and again.
I had a similar problem once. The problem occurred because I made configuration changes without declaring them in the android:configChanges attribute of the <activity> tag (and hence it recreates itself the whole time).
For example, if you change the locale manually you need to add locale to android:configChanges!
It seems to me there is a good chance for endless cycling here if Login is not properly shared between the activities, causing Login.isLoggedIn() to return true in ActivityLogin but false in ActivityMain.
A few critical factors are where your Login object is located, is it static, how is it referenced between Activities? It is entirely possible that ActivityMain is being destroyed while ActivityLogin is active; storing the Login data in SharedPreferences or a database, or otherwise persisting it is important. How does isLoggedIn() resolve (determine its return value?)
Suggestion 1: Consider making use of the Singleton pattern (if you haven't already.)
Suggestion 2: While discouraged, you could store Login at the Application level.
Suggestion 3: You can try using Intent.FLAG_ACTIVITY_SINGLE_TOP to reduce the likelyhood of a new ActivityMain being created - which might not have access to Login, again depending on how you have it stored.
ActivityMain
onResume() {
if(!Login.isLoggedIn()) {
/* Not logged in, launch ActivityLogin! */
Intent intent = new Intent(ActivityMain.this, ActivityLogin.class);
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK|Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
ActivityLogin
onResume() { /* ... */ init(); }
init() {
Login.getUserLoggedIn();
if (Login.isLoggedIn()) {
/* Internet - launch ActivityMain! */
Intent intent = new Intent(ActivityLogin.this, ActivityMain.class);
intent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP); // <--- suggested addition
startActivity(intent);
else if (Network.haveNetworkConnection(Login.getContext()) && Login.checkClientId()) {
/* No internet, the user was unable to login. */
}
I think your main problem is with you onResume function as it gets called each time it comes back into view (eg: you start second activity, finish it, main activity onResume is called again. If you finish your second activity (or it quietly crashes for some reason) you will go back to your mainActivity and call onResume (which will start the cycle all over again).
Now i dont know if you are finishing activity 2 somehow but I would check that.
EDIT:
ALso I would put some logcats here
if (Login.isLoggedIn())
{
//Do Any Additional Setup
Login.setupStuffOnce();
// If user is logged in, open main
Intent intent = new Intent(ActivityLogin.this, ActivityMain.class);
//intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_NEW_TASK);
Log.i("Some Tag", "Starting Main Activity From Activity 2");
startActivity(intent);
}
The above adding of the log.i will allow you to know if this is where the error happens, and you can go from there.
I had similar problem where the activity would be recreated all the time. Re-installing the app wouldn't help, but restarting the phone did the job.

SpeechToText and running the ACTION_CHECK_TTS_DATA intent

I've implemented the TextToSpeech integration exactly as mentioned in this blog post. After I've added it to my program it's now interfering with my other intents.
For example:
List item
User starts app
User invokes load activity
User picks a file to load, and activity returns fileanme to load in the intent
Main activity starts, and realizes it needs to load a filename so it starts doing so
The check for TTS needs to be done so I launch the ACTION_CHECK_TTS_DATA intent
This pauses the main activity again and the loading process gets interrupted
When the TTS check returns, the loading never happened.
When do I need this TTS check? Can I just do it once on application start up? It's causing my application to load slowly. I would like this load to be performed in a separate thread if possible.
Do the check once. Once the data is installed, it's very unlikely that the user will need to ever do it again. Once the data is installed, there's no way for the user to delete it, even if they wanted to.
Also, don't use the ACTION_CHECK_TTS_DATA Intent, that's awkward to use.
Instead, do the following:
Create TextToSpeech
OnInit, check isLanguageAvailable()
if it is, your app is all set.
if not, send the ACTION_INSTALL_TTS_DATA
Here's some code that initializes a TextToSpeech in the way I suggest. As a bonus, it sets the language as well.
public class DemoCreateTTS
{
private static final String TAG = "DemoCreateTTS";
private TextToSpeech tts;
public void createTextToSpeech(final Context context,
final Locale locale)
{
tts = new TextToSpeech(context, new OnInitListener()
{
#Override
public void onInit(int status)
{
if (status == TextToSpeech.SUCCESS)
{
Locale defaultOrPassedIn = locale;
if (locale == null)
{
defaultOrPassedIn = Locale.getDefault();
}
// check if language is available
switch (tts.isLanguageAvailable(defaultOrPassedIn))
{
case TextToSpeech.LANG_AVAILABLE:
case TextToSpeech.LANG_COUNTRY_AVAILABLE:
case TextToSpeech.LANG_COUNTRY_VAR_AVAILABLE:
Log.d(TAG, "SUPPORTED");
tts.setLanguage(locale);
//pass the tts back to the main
//activity for use
break;
case TextToSpeech.LANG_MISSING_DATA:
Log.d(TAG, "MISSING_DATA");
Log.d(TAG, "require data...");
Intent installIntent = new Intent();
installIntent.setAction(TextToSpeech.Engine.ACTION_INSTALL_TTS_DATA);
context.startActivity(installIntent);
break;
case TextToSpeech.LANG_NOT_SUPPORTED:
Log.d(TAG, "NOT SUPPORTED");
break;
}
}
}
});
}
}

Categories

Resources