java – Run App Twice To Work-ThrowExceptions

Exception or error:

I’m making an android app that test if certain security features on your phone are enabled. For example, if you have password log in enabled or if your data is encrypted on your phone.

For some reason, the app has to be run twice to test and see if these security features are enabled on the phone or not, and this is the problem I’m trying to solve. I’d like it to test and see if the security features are enabled when the app is created and the first time the app is run, not the second time it is run.

I test if these features are enabled in the onStart() function in my MainActivity file. I included the functions code below:

    @Override
    @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
    @SuppressLint("NewApi")
    public void onStart()
    {
        super.onStart();

        //determine if phone uses lock pattern
        //It returns 1 if pattern lock enabled and 0 if pin/password password enabled
        ContentResolver cr = getBaseContext().getContentResolver();
        lockPatternEnable = Settings.Secure.getInt(cr, Settings.Secure.LOCK_PATTERN_ENABLED, 0);//Settings.System 


        //returns 1 if pin/password protected. 0 if not
        KeyguardManager keyguardManager = (KeyguardManager) getBaseContext().getSystemService(Context.KEYGUARD_SERVICE);
        if( keyguardManager.isKeyguardSecure()) 
        {
           //it is pin or password protected
           pinPasswordEnable=1;
        } 
        else 
        {
           //it is not pin or password protected 
            pinPasswordEnable=0;
        }//http://stackoverflow.com/questions/6588969/device-password-in-android-is-existing-or-not/18716253#18716253

        //determine if adb is enabled. works
        adb=Settings.Global.getInt(cr, Settings.Global.ADB_ENABLED, 0);

        //determine if bluetooth is enabled.works
        bluetooth=Settings.Global.getInt(cr, Settings.Global.BLUETOOTH_ON, 0);
        //Settings.System BLUETOOTH_DISCOVERABILITY

        //determine if wifi is enabled. works
        WifiManager wifi = (WifiManager)getSystemService(Context.WIFI_SERVICE);
        if (wifi.isWifiEnabled())
        {
            //wifi is enabled
            wifiInt=1;
        }
        else
            wifiInt=0;

        //determine if data is encrypted
        getDeviceEncryptionencryption();

        //determine if gps enabled


    }//end of onStart() function

If any more code needs to be posted to answer this question, just let me know, and thanks for your help. Maybe the issue has something to do with the super.onStart();

Does anyone think that a splash loading screen might help solve the issue?

How to solve:

Here is good explanation how app lifecycle flows.
onStart() can be executed many times. You can keep counter how many times you had entered this method and act differently on each time:

 static int counter=0;
 public void onStart()
    {
      counter++;
      Log.i("MyApp", "onStart() run "+counter);
      switch (counter){
        case 1: break; // first run
        case 2: break; // second run
        default: break;// other runs
      }
 }

To be more clear about life cycle and why your onStart() method is called twice I suggest to have counter and Log.i() in each important state of the cycle – at least in onCreate() and onRestart().

Keep in mind that app stays in memory when you click Home button. When you click app icon again it restarts already running app (calls onRestart() and then onStart() methods and no onCreate() ). When you really kill you app for real then sequence would be onCreate and onStart without onRestart. Having logcat records really helps you to understand app lifecycle flow and why your onStart() is called twice or more times.

###

Using a static variable to check how many times onStart has been called isn’t a good idea, because an app can be killed if Android needs more memory for other apps while still allowing the user to navigate back to the app. That would be the path through the red box in the picture below (http://developer.android.com/reference/android/app/Activity.html#ActivityLifecycle):

enter image description here

A static variable would be 0 again after that and your app would run the security check again.
What you need to do is use an instance variable that you persist in onSaveInstanceState and restore in onCreate. In case the app is killed, onSaveInstanceState is called and you save your Activity’s state. If the user goes back to the app, onCreate is called and the state would be restored. This works for all other cases too when the app isn’t killed but the user just navigates away from the app and later re-opens it. Here’s a simple example of an app saving and restoring:

public class MainActivity extends Activity {

    private boolean mSecurityCheckDone;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        if (savedInstanceState != null) {
            mSecurityCheckDone = savedInstanceState.getBoolean("mSecurityCheckDone");
        }
    }

    @Override
    protected void onStart() {
        super.onStart();

        if (! mSecurityCheckDone) {
            // run the security check

            mSecurityCheckDone = true;
        }
    }

    @Override
    public void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);

        outState.putBoolean("mSecurityCheckDone", mSecurityCheckDone);
    }

    @Override
    public void onRestoreInstanceState(Bundle savedInstanceState) {
        super.onRestoreInstanceState(savedInstanceState);

        if (savedInstanceState != null) {
            mSecurityCheckDone = savedInstanceState.getBoolean("mSecurityCheckDone");
        }
    }

}

###

how about using flag ?

singleTop

If an instance of the activity already exists at the top of the target
task, the system routes the intent to that instance through a call to
its onNewIntent() method, rather than creating a new instance of the
activity.

singleTask

The system creates the activity at the root of a new task and routes
the intent to it. However, if an instance of the activity already
exists, the system routes the intent to existing instance through a
call to its onNewIntent() method, rather than creating a new one.

singleInstance

Same as “singleTask”, except that the system doesn’t launch any other
activities into the task holding the instance. The activity is always
the single and only member of its task.

http://developer.android.com/guide/topics/manifest/activity-element.html

###

I’m not sure why you are using onStart(), if you want it to be run the first time the activity is created I would probably use onCreate() instead.

There is no API in Android that will tell you if the app has been run at least once so you will need to use some type of persistent storage for that, e.g. SharedPreferences could be used to persist a flag that would be set the first time your app is run and thereafter you can check it as shown here.

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    SharedPreferences settings = getSharedPreferences("Prefs", 0);
    if (settings.getBoolean("first_time", true)) {
        //the app is being launched for first time, do something        
        Log.d("Comments", "First time");

        // first time task

        // record the fact that the app has been started at least once
        settings.edit().putBoolean("first_time", false).commit(); 
    }
}

Leave a Reply

Your email address will not be published. Required fields are marked *