I'm testing out a notification that tells the user of an Android app whether or not there is an internet connection. I have inserted the code that does this into the onResume function, as seen below:
#Override
protected void onResume(){
super.onResume();
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setPositiveButton(R.string.OK, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
dialog.dismiss();
}
});
if(isNetworkConnected()){
builder.setMessage(R.string.yes_internet)
.setTitle(R.string.title);
}
else{
builder.setMessage(R.string.no_internet)
.setTitle(R.string.title);
}
AlertDialog dialog = builder.create();
dialog.show();
}
private boolean isNetworkConnected() {
ConnectivityManager cm = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo ni = cm.getActiveNetworkInfo();
if (ni == null) {
// There are no active networks.
return false;
}
else{
return true;
}
}
Which works just fine. Except for the part where after you log in, see the alert, and dismiss it, another identical alert appears. This only happens after logging in, it does not happen if you leave the app and then come back to it. My login activity (which is the one automatically generated by Eclipse) is called from onCreate, so that it will only run when the app is launched. So, it would appear that something about the login activity is causing onResume to be called twice. But I have no idea what that could be.
Here is the code for the login activity:
/**
* Activity which displays a login screen to the user, offering registration as
* well.
*/
public class LoginActivity extends Activity {
/**
* A dummy authentication store containing known user names and passwords.
* TODO: remove after connecting to a real authentication system.
*/
private static final String[] DUMMY_CREDENTIALS = new String[] {
"foo#example.com:hello", "bar#example.com:world" };
/**
* The default email to populate the email field with.
*/
public static final String EXTRA_EMAIL = "com.example.android.authenticatordemo.extra.EMAIL";
/**
* Keep track of the login task to ensure we can cancel it if requested.
*/
private UserLoginTask mAuthTask = null;
// Values for email and password at the time of the login attempt.
private String mEmail;
private String mPassword;
// UI references.
private EditText mEmailView;
private EditText mPasswordView;
private View mLoginFormView;
private View mLoginStatusView;
private TextView mLoginStatusMessageView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_login);
// Set up the login form.
mEmail = getIntent().getStringExtra(EXTRA_EMAIL);
mEmailView = (EditText) findViewById(R.id.email);
mEmailView.setText(mEmail);
mPasswordView = (EditText) findViewById(R.id.password);
mPasswordView
.setOnEditorActionListener(new TextView.OnEditorActionListener() {
#Override
public boolean onEditorAction(TextView textView, int id,
KeyEvent keyEvent) {
if (id == R.id.login || id == EditorInfo.IME_NULL) {
attemptLogin();
return true;
}
return false;
}
});
mLoginFormView = findViewById(R.id.login_form);
mLoginStatusView = findViewById(R.id.login_status);
mLoginStatusMessageView = (TextView) findViewById(R.id.login_status_message);
findViewById(R.id.sign_in_button).setOnClickListener(
new View.OnClickListener() {
#Override
public void onClick(View view) {
attemptLogin();
}
});
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
super.onCreateOptionsMenu(menu);
getMenuInflater().inflate(R.menu.login, menu);
return true;
}
/**
* Attempts to sign in or register the account specified by the login form.
* If there are form errors (invalid email, missing fields, etc.), the
* errors are presented and no actual login attempt is made.
*/
public void attemptLogin() {
if (mAuthTask != null) {
return;
}
// Reset errors.
mEmailView.setError(null);
mPasswordView.setError(null);
// Store values at the time of the login attempt.
mEmail = mEmailView.getText().toString();
mPassword = mPasswordView.getText().toString();
boolean cancel = false;
View focusView = null;
// Check for a valid password.
if (TextUtils.isEmpty(mPassword)) {
mPasswordView.setError(getString(R.string.error_field_required));
focusView = mPasswordView;
cancel = true;
} else if (mPassword.length() < 4) {
mPasswordView.setError(getString(R.string.error_invalid_password));
focusView = mPasswordView;
cancel = true;
}
// Check for a valid email address.
if (TextUtils.isEmpty(mEmail)) {
mEmailView.setError(getString(R.string.error_field_required));
focusView = mEmailView;
cancel = true;
} else if (!mEmail.contains("#")) {
mEmailView.setError(getString(R.string.error_invalid_email));
focusView = mEmailView;
cancel = true;
}
if (cancel) {
// There was an error; don't attempt login and focus the first
// form field with an error.
focusView.requestFocus();
} else {
// Show a progress spinner, and kick off a background task to
// perform the user login attempt.
mLoginStatusMessageView.setText(R.string.login_progress_signing_in);
showProgress(true);
mAuthTask = new UserLoginTask();
mAuthTask.execute((Void) null);
}
}
/**
* Shows the progress UI and hides the login form.
*/
#TargetApi(Build.VERSION_CODES.HONEYCOMB_MR2)
private void showProgress(final boolean show) {
// On Honeycomb MR2 we have the ViewPropertyAnimator APIs, which allow
// for very easy animations. If available, use these APIs to fade-in
// the progress spinner.
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR2) {
int shortAnimTime = getResources().getInteger(
android.R.integer.config_shortAnimTime);
mLoginStatusView.setVisibility(View.VISIBLE);
mLoginStatusView.animate().setDuration(shortAnimTime)
.alpha(show ? 1 : 0)
.setListener(new AnimatorListenerAdapter() {
#Override
public void onAnimationEnd(Animator animation) {
mLoginStatusView.setVisibility(show ? View.VISIBLE
: View.GONE);
}
});
mLoginFormView.setVisibility(View.VISIBLE);
mLoginFormView.animate().setDuration(shortAnimTime)
.alpha(show ? 0 : 1)
.setListener(new AnimatorListenerAdapter() {
#Override
public void onAnimationEnd(Animator animation) {
mLoginFormView.setVisibility(show ? View.GONE
: View.VISIBLE);
}
});
} else {
// The ViewPropertyAnimator APIs are not available, so simply show
// and hide the relevant UI components.
mLoginStatusView.setVisibility(show ? View.VISIBLE : View.GONE);
mLoginFormView.setVisibility(show ? View.GONE : View.VISIBLE);
}
}
/**
* Represents an asynchronous login/registration task used to authenticate
* the user.
*/
public class UserLoginTask extends AsyncTask<Void, Void, Boolean> {
#Override
protected Boolean doInBackground(Void... params) {
// TODO: attempt authentication against a network service.
try {
// Simulate network access.
Thread.sleep(2000);
} catch (InterruptedException e) {
return false;
}
for (String credential : DUMMY_CREDENTIALS) {
String[] pieces = credential.split(":");
if (pieces[0].equals(mEmail)) {
// Account exists, return true if the password matches.
return pieces[1].equals(mPassword);
}
}
// TODO: register the new account here.
return true;
}
#Override
protected void onPostExecute(final Boolean success) {
mAuthTask = null;
showProgress(false);
if (success) {
finish();
} else {
mPasswordView
.setError(getString(R.string.error_incorrect_password));
mPasswordView.requestFocus();
}
}
#Override
protected void onCancelled() {
mAuthTask = null;
showProgress(false);
}
}
I think this is possible scenario where your MainActivity's onResume is called twice, I assume that you start LoginActivity in MainActivity's onCreate:
MainActivity is created and LoginActivity is launched. MainActivity still continues its lifecycle - onResume is called (and onPause right after etc..)...
When you finish your LoginActivity, then MainActivity is resumed again - onResume is called for the second time.
You can consider saving some boolean value (or the whole dialog) to preserve showing the dialog for the second time, or you can change your workflow so that MainActivity is started AFTER successful login.
It's not possible to detect the error from the code that you posted so far.
You should make sure you study the following picture a little bit and refactor your code with it in mind.
Make sure that calls to other activities/methods do not pause/resume your main activity multiple times! That would only cause onResume() to be called several times.
From http://developer.android.com/training/basics/activity-lifecycle/starting.html
Related
I'm trying to shows a ProgressDialog while a list is loading data in an AsyncTask, but 'exito' in onPostExecute is never true, and the dialog never dismiss.
I tried to delete the if (exito) but the progressDialog dismiss and the list is charged a few seconds later, and it isn't I want.
I want that progressDialog shows while is loading, and when is loaded, dismiss the progressDialog and change fragment.
Where is my mistake? Thanks
private class ATCargarProductos extends AsyncTask<Void, Integer, Boolean>{
boolean terminado = false;
Bundle bdl;
FragmentTransaction transaction;
ProgressDialog progressDialog;
ArrayList<ItemDetails> results = new ArrayList<ItemDetails>();
public ATCargarProductos(FragmentTransaction transaction){
this.transaction = transaction;
}
#Override
protected Boolean doInBackground(Void... params) {
if (compruebaConexion()) {
rellenaLista(new CallBack() {
#Override
public void onSuccess(final ArrayList<Comida> listaComidas) {
for (int i = 0; i < listaComidas.size(); i++) {
ItemDetails item_details = new ItemDetails(listaComidas.get(i));
if (item_details.getTipo().equals("B")) {
results.add(item_details);
}
}
Fragment fragmentProductos = new FragmentProductos();
bdl = new Bundle(2);
bdl.putInt("tipoProducto", 1);
bdl.putParcelableArrayList("resultados", results);
fragmentProductos.setArguments(bdl);
completado = true;
}
#Override
public void onFail(String msg) {
}
});
return completado;
} else {
return false;
}
}
#Override
protected void onPreExecute() {
super.onPreExecute();
progressDialog = new ProgressDialog(getActivity(), R.style.AppTheme_Dark_Dialog);
progressDialog.setIndeterminate(true);
progressDialog.setMessage("Cargando lista...");
progressDialog.show();
}
#Override
protected void onPostExecute(Boolean exito) {
super.onPostExecute(exito);
if (exito) {
progressDialog.dismiss();
transaction.commit();
}
}
}
rellenaLista() is asynchronous.
Since it's running on a different thread, return completado; is executed before you reach onSuccess(), and therefore completado is still false.
You don't really need an AsyncTask.
You can do the following:
if (compruebaConexion()) {
// show progress dialog here
rellenaLista(new CallBack() {
#Override
public void onSuccess(final ArrayList<Comida> listaComidas) {
// dismiss dialog
// handle success
}
#Override
public void onFail(String msg) {
// dismiss dialog
// handle failure
}
});
}
I think that the method compruebaConexion()is always false, if you can add to the question the code of this method. I could admit this idea.
Create a class like that. And check your internet connection with it.
public class EZInternetConnection {
public static boolean isNetworkConnected(Context context)
{
ConnectivityManager cm =
(ConnectivityManager)context.getSystemService(Context.CONNECTIVITY_SERVICE);
boolean flag = cm.getActiveNetworkInfo() != null &&
cm.getActiveNetworkInfo().isConnectedOrConnecting();
return flag;
}
}
Usage:
if(EZInternetConnection.isNetworkConnected( context ))
{
//internet connection is ok.
//other codes.
}
else
{
//no internet.
}
I have an Activity with ViewPager PagerSlidingTabStrip for each page of my ViewPager has a fragment, and in each fragment realize an http request (using Volley) to load the data from the page, but when the request ends in error, type timeout or lost connection, I need to display a dialog with the option to redo the call to the server, the problem to prevent multiple dialogs are open for each error is resolved with the snippet:
See this solution here: http://www.jorgecoca.com/android-quick-tip-avoid-opening-multiple-dialogs-when-tapping-an-element/
#Override
public void show(FragmentManager manager, String tag) {
if (manager.findFragmentByTag(tag) == null) {
super.show(manager, tag);
}
}
When the user clicks the dialog button to try again, and the dialog closed and taken to check if there is internet connection, if I'm not, the dialog should be opened again, but the dialog is not displayed again, I believe that the tag does not was released to FragmentManager.
Code in Activity:
final Button mButton = ( Button ) this.findViewById( R.id.btn_opendialog );
final DialogFragmentHelper mDialog = new DialogFragmentHelper();
mDialog.setCallbackListener( new OnCallback() {
#Override
public void onCancel() {
}
#Override
public void onConfirm() {
// verify if network available
mDialog.show( MainActivity.this.getSupportFragmentManager(), DialogFragmentHelper.DIALOG_TAG );
}
} );
mButton.setOnClickListener( new OnClickListener() {
#Override
public void onClick( final View v ) {
mDialog.show( MainActivity.this.getSupportFragmentManager(), DialogFragmentHelper.DIALOG_TAG );
}
} );
Would someone have a suggestion of a workaround?
In order to maintain the structure that is ready in my project, and also keep something closer to my goal, which is to use no flags, nor pass control of a third dialogfragment to manage, arrived at a solution that'll take an hour as a result.
DialogFragmentHelper mDialog = new DialogFragmentHelper();
mDialog.setCallbackListener( new OnCallback() {
#Override
public void onCancel() {}
#Override
public void onConfirm() {
mDialog.dismissAllowingStateLoss();
if(networkAvailable == false){
new Handler().post( new Runnable() {
#Override
public void run() {
mDialog.show( MainActivity.this.getSupportFragmentManager(), DialogFragmentHelper.DIALOG_TAG );
}
} );
}else {
//do something here
}
}
} );
this way I guarantee that while several requests are sent to open the dialogfragment, only the first is executed, and closing the dialogfragment, I can quickly open it again if needed, as can happen in the scenario I'm working.
You could approach it with a singleton controller. E.g.:
package com.example.stackoverflowsandbox;
public class MyDialogController {
private static MyDialogController instance;
public static MyDialogController getInstance() {
if ( MyDialogController.instance == null ) {
MyDialogController.instance = new MyDialogController();
}
return MyDialogController.instance;
}
private boolean dialogOpenned;
private MyDialogController() {}
public void closeDialog() {
if ( this.dialogOpenned ) {
this.dialogOpenned = false;
// you close code...
}
}
public void openDialog() {
if ( !this.dialogOpenned ) {
this.dialogOpenned = true;
// your open code...
}
}
}
I have a problem with an android application. I want to make a login screen, and I have an async task that should run when the login button is pressed. However, it appears that the runs automatically when the application starts, and I can't figure out why.
This is my code:
package com.connect.application;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.annotation.TargetApi;
import android.app.Activity;
import android.content.Intent;
import android.os.AsyncTask;
import android.os.Build;
import android.os.Bundle;
import android.text.TextUtils;
import android.util.Log;
import android.view.KeyEvent;
import android.view.Menu;
import android.view.View;
import android.view.inputmethod.EditorInfo;
import android.widget.EditText;
import android.widget.TextView;
import com.connect.utils.*;
/**
* Activity which displays a login screen to the user, offering registration as
* well.
*/
public class LoginActivity extends Activity {
/**
* A dummy authentication store containing known user names and passwords.
* TODO: remove after connecting to a real authentication system.
*/
// private static final String[] DUMMY_CREDENTIALS = new String[]{
// "foo#example.com:hello",
// "bar#example.com:world"
// };
/**
* The default email to populate the email field with.
*/
public static final String EXTRA_EMAIL = "com.example.android.authenticatordemo.extra.EMAIL";
/**
* Keep track of the login task to ensure we can cancel it if requested.
*/
private UserLoginTask mAuthTask = null;
// Values for email and password at the time of the login attempt.
private String mEmail;
private String mPassword;
// UI references.
private EditText mEmailView;
private EditText mPasswordView;
private View mLoginFormView;
private View mLoginStatusView;
private TextView mLoginStatusMessageView;
private Boolean mLoggedIn = false;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_login);
// Set up the login form.
mEmail = getIntent().getStringExtra(EXTRA_EMAIL);
mEmailView = (EditText) findViewById(R.id.email);
mEmailView.setText(mEmail);
mPasswordView = (EditText) findViewById(R.id.password);
// mPasswordView.setOnEditorActionListener(new TextView.OnEditorActionListener() {
// #Override
// public boolean onEditorAction(TextView textView, int id, KeyEvent keyEvent) {
// if (id == R.id.login || id == EditorInfo.IME_NULL) {
// attemptLogin();
// return true;
// }
// return false;
// }
// });
mLoginFormView = findViewById(R.id.login_form);
mLoginStatusView = findViewById(R.id.login_status);
mLoginStatusMessageView = (TextView) findViewById(R.id.login_status_message);
findViewById(R.id.sign_in_button).setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Log.v("TAG/Login clicked", "Login button clicked");
attemptLogin();
}
});
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
super.onCreateOptionsMenu(menu);
getMenuInflater().inflate(R.menu.login, menu);
return true;
}
/**
* Attempts to sign in or register the account specified by the login form.
* If there are form errors (invalid email, missing fields, etc.), the
* errors are presented and no actual login attempt is made.
*/
public void attemptLogin() {
if (mAuthTask != null) {
return;
}
// Reset errors.
mEmailView.setError(null);
mPasswordView.setError(null);
// Store values at the time of the login attempt.
mEmail = mEmailView.getText().toString();
mPassword = mPasswordView.getText().toString();
boolean cancel = false;
View focusView = null;
// Check for a valid password.
if (TextUtils.isEmpty(mPassword)) {
mPasswordView.setError(getString(R.string.error_field_required));
focusView = mPasswordView;
cancel = true;
} else if (mPassword.length() < 4) {
mPasswordView.setError(getString(R.string.error_invalid_password));
focusView = mPasswordView;
cancel = true;
}
// Check for a valid email address.
if (TextUtils.isEmpty(mEmail)) {
mEmailView.setError(getString(R.string.error_field_required));
focusView = mEmailView;
cancel = true;
} else if (!mEmail.contains("#")) {
mEmailView.setError(getString(R.string.error_invalid_email));
focusView = mEmailView;
cancel = true;
}
if (cancel) {
// There was an error; don't attempt login and focus the first
// form field with an error.
focusView.requestFocus();
} else {
// Show a progress spinner, and kick off a background task to
// perform the user login attempt.
mLoginStatusMessageView.setText(R.string.login_progress_signing_in);
showProgress(true);
mAuthTask = new UserLoginTask();
String[] credentials = new String[2];
credentials[0] = mEmail;
credentials[1] = mPassword;
Log.v("TAG/Auth task started", "Auth task started");
mAuthTask.execute(credentials);
}
}
/**
* Shows the progress UI and hides the login form.
*/
#TargetApi(Build.VERSION_CODES.HONEYCOMB_MR2)
private void showProgress(final boolean show) {
// On Honeycomb MR2 we have the ViewPropertyAnimator APIs, which allow
// for very easy animations. If available, use these APIs to fade-in
// the progress spinner.
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR2) {
int shortAnimTime = getResources().getInteger(android.R.integer.config_shortAnimTime);
mLoginStatusView.setVisibility(View.VISIBLE);
mLoginStatusView.animate()
.setDuration(shortAnimTime)
.alpha(show ? 1 : 0)
.setListener(new AnimatorListenerAdapter() {
#Override
public void onAnimationEnd(Animator animation) {
mLoginStatusView.setVisibility(show ? View.VISIBLE : View.GONE);
}
});
mLoginFormView.setVisibility(View.VISIBLE);
mLoginFormView.animate()
.setDuration(shortAnimTime)
.alpha(show ? 0 : 1)
.setListener(new AnimatorListenerAdapter() {
#Override
public void onAnimationEnd(Animator animation) {
mLoginFormView.setVisibility(show ? View.GONE : View.VISIBLE);
}
});
} else {
// The ViewPropertyAnimator APIs are not available, so simply show
// and hide the relevant UI components.
mLoginStatusView.setVisibility(show ? View.VISIBLE : View.GONE);
mLoginFormView.setVisibility(show ? View.GONE : View.VISIBLE);
}
}
/**
* Represents an asynchronous login/registration task used to authenticate
* the user.
*/
public class UserLoginTask extends AsyncTask<String, Void, Boolean> {
#Override
protected Boolean doInBackground(String... params) {
// TODO: attempt authentication against a network service.
// try {
// // Simulate network access.
// Thread.sleep(2000);
// } catch (InterruptedException e) {
// return false;
// }
//
// for (String credential : DUMMY_CREDENTIALS) {
// String[] pieces = credential.split(":");
// if (pieces[0].equals(mEmail)) {
// // Account exists, return true if the password matches.
// return pieces[1].equals(mPassword);
// }
// }
Log.v("TAG/LoginAsync", "Task triggerred");
LoggedUser.getInstance().setId(1);
LoggedUser.getInstance().setmUsername("dummy#mail.com");
// TODO: register the new account here.
return true;
}
#Override
protected void onPostExecute(final Boolean success) {
mAuthTask = null;
showProgress(false);
if (success) {
Intent intent = new Intent(LoginActivity.this, MainActivity.class);
startActivity(intent);
mLoggedIn = true;
finish();
} else {
mPasswordView.setError(getString(R.string.error_incorrect_password));
mPasswordView.requestFocus();
}
}
#Override
protected void onCancelled() {
mAuthTask = null;
showProgress(false);
}
}
}
And this is what appears in my log when I run the application:
01-16 14:36:01.593 13706-13706/com.connect.application V/TAG/Login clicked﹕ Login button clicked
01-16 14:36:01.597 13706-13706/com.connect.application V/TAG/Auth task started﹕ Auth task started
01-16 14:36:01.601 13706-13742/com.connect.application V/TAG/LoginAsync﹕ Task triggerred
, without pressing any buttons. Any help would be appreciated.
Im having trouble adding a spinner in place of the application name in my action bar.
im sure this question has been asked before but all the answers are pretty much the same either a simple one line correction and then a reference to thiers a lovely example at the google dev site here: http://developer.android.com/guide/topics/ui/actionbar.html#Dropdown
the android docs but for a beginner I find it ashumes to much and leaves out tiny peices of key information.
public class MainProgram extends Activity implements OnNavigationListener {
/**
* Mobile Service Client reference
*/
private MobileServiceClient mClient;
private ConnectWithService service;
/**
* Progress spinner to use for table operations
*/
private ProgressBar mProgressBar;
/**
* Sensor stuff
*/
SensorManager mSensor;
Detection orientation;
//Spinner Listener
mOnNavigationListener = new OnNavigationListener() {
// Get the same strings provided for the drop-down's ArrayAdapter
String[] strings = getResources().getStringArray(R.array.action_list);
#Override
public boolean onNavigationItemSelected(int position, long itemId) {
//toast
Toast toast = Toast.makeText(this, "whoop whoop!", toast.LENGTH_SHORT);
toast.show();
}
};
/**
* Initializes the activity
*/
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main_program);
//Load progress bar view
mProgressBar = (ProgressBar) findViewById(R.id.loadingProgressBar);
// Initialize the progress bar
mProgressBar.setVisibility(ProgressBar.GONE);
//Spinner Adapter
setNavigationMode(NAVIGATION_MODE_LIST);
SpinnerAdapter mSpinnerAdapter = ArrayAdapter.createFromResource(this, R.array.action_list,
android.R.layout.simple_spinner_dropdown_item);
//innitialize Sensor Manager
mSensor = (SensorManager)getSystemService(SENSOR_SERVICE);
//signin
try {
// Create the Mobile Service Client instance, using the provided
// Mobile Service URL and key
mClient = new MobileServiceClient(
"secret",
"secret",
this).withFilter(new ProgressFilter());
} catch (MalformedURLException e) {
createAndShowDialog(new Exception("There was an error creating the Mobile Service. Verify the URL"), "Error");
}
authenticate();
}
/**
* Initializes the activity menu
*/
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.activity_main, menu);
return true;
}
/**
* Select an option from the menu
*/
#Override
public boolean onOptionsItemSelected(MenuItem item) {
if (item.getItemId() == R.id.menu_refresh) {
}
return true;
}
/**
* Creates a dialog and shows it
*
* #param exception
* The exception to show in the dialog
* #param title
* The dialog title
*/
private void createAndShowDialog(Exception exception, String title) {
createAndShowDialog(exception.toString(), title);
}
/**
* Creates a dialog and shows it
*
* #param message
* The dialog message
* #param title
* The dialog title
*/
private void createAndShowDialog(String message, String title) {
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setMessage(message);
builder.setTitle(title);
builder.create().show();
}
private class ProgressFilter implements ServiceFilter {
#Override
public void handleRequest(ServiceFilterRequest request, NextServiceFilterCallback nextServiceFilterCallback,
final ServiceFilterResponseCallback responseCallback) {
runOnUiThread(new Runnable() {
#Override
public void run() {
if (mProgressBar != null) mProgressBar.setVisibility(ProgressBar.VISIBLE);
}
});
nextServiceFilterCallback.onNext(request, new ServiceFilterResponseCallback() {
#Override
public void onResponse(ServiceFilterResponse response, Exception exception) {
runOnUiThread(new Runnable() {
#Override
public void run() {
if (mProgressBar != null) mProgressBar.setVisibility(ProgressBar.GONE);
}
});
if (responseCallback != null) responseCallback.onResponse(response, exception);
}
});
}
}
private void authenticate() {
// Login using the Google provider.
mClient.login(MobileServiceAuthenticationProvider.MicrosoftAccount,
new UserAuthenticationCallback() {
#Override
public void onCompleted(MobileServiceUser user,
Exception exception, ServiceFilterResponse response) {
if (exception == null) {
createAndShowDialog(String.format(
"You are now logged in - %1$2s",
user.getUserId()), "Success");
service = new ConnectWithService(mClient,user.getUserId());
orientation = new Detection(mSensor);
} else {
createAndShowDialog("You must log in. Login Required", "Error");
}
}
});
}
//start sensors camera etc if needed
protected void onResume() {
super.onResume();
if(orientation!=null)
orientation.startSensorsListening();
}
// stop sensors etc
protected void onPause() {
super.onPause();
orientation.stopSensorListening();
}
}
theres at least two errors i think mOnNavigationListener should be somewhere else
setnavigationMode() has an error
don't use OnNavigationListener with (ActionBar.NAVIGATION_MODE_LIST)
use:
final ActionBar bar = getActionBar();
bar.setDisplayShowCustomEnabled(true);
bar.setCustomView(R.layout.action_bar_custom);
then all as normal.
spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
#Override
public void onItemSelected(AdapterView<?>....
I am developing an application that needs to display a passcode screen whenever a user leaves the app and comes back (be it through a screen lock, or going back to the home screen through the back or home button). I had it working using the following:
The starting activity would call for the passcode check on startup, and each activity added the following functionality to their onPause method:
#Override
public void onPause() {
super.onPause();
if (!isFinishing()) {
new PasscodeCheckTask(this.getApplicationContext(),this).execute();
}
}
The PassocdeCheckTask looks like the following. It checks to see if the screen is off or the app is no longer in the background
public class PasscodeCheckTask extends AsyncTask<Void, Void, Boolean> {
public static final int CHECK_PASSCODE = 0;
private Context mActivityApplicationContext;
private Context mActivityContext;
public PasscodeCheckTask(Context applicationContext, Context activityContext){
mActivityApplicationContext = applicationContext;
mActivityContext = activityContext;
}
#Override
protected Boolean doInBackground(Void... params) {
Boolean result = false;
if (!((PowerManager)mActivityApplicationContext.getSystemService(android.content.Context.POWER_SERVICE)).isScreenOn() ||
!isAppOnForeground(mActivityApplicationContext)) {
result = true;
}
return result;
}
#Override
protected void onPostExecute(Boolean result) {
if (result) {
// Start passcode activity to check for passcode
/* CODE HERE */
((Activity)mActivityContext).startActivityForResult(intent, CHECK_PASSCODE);
}
}
protected boolean isAppOnForeground(final Context context) {
List<RunningAppProcessInfo> appProcesses = ((ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE)).getRunningAppProcesses();
if (appProcesses == null) {
return false;
}
final String packageName = context.getPackageName();
for (RunningAppProcessInfo appProcess : appProcesses) {
if ((appProcess.importance == RunningAppProcessInfo.IMPORTANCE_FOREGROUND) &&
appProcess.processName.equals(packageName)) {
return true;
}
}
return false;
}
}
The Passcode activity would finish when done, and the calling activity would moveTaskToBackground(true) if the passcode didn't pass. This system worked beautifully until I tried it on an HTC Evo with mikg ROM. For some reason, the appProcess.importance never showed up as IMPORTANCE_FOREGROUND. It was always IMPORTANCE_BACKGROUND. Thus, the passcode would ALWAYS be brought up, even though the app never went into the background.
I tried DropBox on that phone (which has a passcode lock as well), and it worked beautifully. I can't seem to find a different way to know when an app has gone to the background, or if it is being brought back from the background. Any ideas on how to make this work?
In onStop() of each activity, update a static data member with the time you left the activity. In onStart() of each activity, check that time, and if it exceeds some timeout threshold, display your authentication activity. Allow the user to set the timeout value, so that if they don't want to be bothered every few seconds, they can control that.
I liked the time based approach, I've been struggling for a while getting this to work in a nice way. The time based approach works well. I made a class for easier usage.
public class PinCodeCheck {
private static long INIT_TIME = 0;
private static PinCodeCheck ref = null;
private static SharedPreferences values = null;
private PinCodeCheck(Context context){
values = context.getSharedPreferences("com.example.xxx", 0); //use your preferences file name key!
}//end constructor
public static synchronized PinCodeCheck getInstance(Context context) {
if (ref == null){
ref = new PinCodeCheck(context);
}
return ref;
}//end method
public void init(){
PinCodeCheck.INIT_TIME = System.currentTimeMillis();
}//end method
public void forceLock(){
PinCodeCheck.INIT_TIME = 0;
}//end method
public boolean isLocked(){
long currentTime = System.currentTimeMillis();
long threshold = values.getLong(Keys.PASSWORD_PROTECT_TIMEOUT, 30000); // check here, might change in between calls
if (currentTime - PinCodeCheck.INIT_TIME > threshold){
return true;
}
return false;
}//end method
}//end class
USAGE
private static PinCodeCheck check = PinCodeCheck.getInstance(context);
#Override
public void onResume() {
super.onResume();
if (check.isLocked()) {
showDialog();
}
}//end method
#Override
public void onPause() {
super.onPause();
check.init();
}//end method