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 ran 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?
super.onStart(); is fine. Splash screen will not help.
From your code I do not see how you determine how many times it ran.
You also mention testing - is it manual testing or you use any framework? Maybe your framework has some init method which runs before each run and it makes this extra call for onStart().
Issues is not in this code. Use debugger or logcat and figure out who calls you twice and, as #nasch had asked, what happens at first run.
Still, real question to help you remains - what do you mean "call twice". Is it you manually clicking app icon twice or is it some testing framework calls your app twice. Both cases are clear to solve.
Related
I have an Android app that serves content via webview. I've implemented a network connectivity alert so if my users are in a location where they can't get internet, I show a message. This takes place inside the onReceivedError method. It works as expected; if I disable all internet connections, I get a warning message. However, even when internet connection exists, the warning message still shows. If I minimize my app, open the native browser and visit 8-10 links, when I switch back to my app, I am given the network warning even though the device is connected to the network.
This only happens on one of my 6 test devices (my current phone, a Samsung Galaxy S10e. The problem does not occur on 5 different Android devices, both newer and older. I'm just looking for a way to ignore the warning when the app is in the background state. I've searched for an easy way to do this, but I haven't found anything simple that doesn't involve writing a new class.
How can I write a conditional statement to do nothing when the onReceivedError method is triggered while the app is in the background? Here is a portion of my code, along with what I would like to have happen:
#override
public void onReceivedError(WebView view, WebResourceRequest request, WebResourceError error) {
// the part I need help with
if ("app in background"){
// do nothing
} else {
// this is where I have employed my notification, a snackbar
}
}
Thank you for your help!
My apps on the Google Play store are affected by the Intent Redirection Vulnerability (see article https://support.google.com/faqs/answer/9267555)
I implemented "Option 2" on the recommended solutions yet the warning is still being reported.
I've tried several different ways of verifying the calling activity, but nothing passes whatever check they're doing.
Here's their recommended solution:
// check if the originating Activity is from trusted package
if (getCallingActivity().getPackageName().equals(“known”)) {
Intent intent = getIntent();
// extract the nested Intent
Intent forward = (Intent) intent.getParcelableExtra(“key”);
// redirect the nested Intent
startActivity(forward);
}
And here's my code:
public void onFinish() {
finish();
// check if the originating Activity is from trusted package
if (getCallingActivity() != null &&
getCallingActivity().getPackageName().equals(
PerfectCommon.getAppContext().getPackageName())) {
Intent intent = null;
// extract the nested Intent
intent =
getIntent().getParcelableExtra(BaseActivity.ORIG_ACTIVITY);
if (intent != null){
// redirect the nested Intent
startActivity(intent);
return;
}
}
Intent newIntent;
SplashActivity context = SplashActivity.this;
boolean portrait = PerfectCommon.portraitMode;
ArrayList<Intent> intents = new ArrayList<>();
// Create intent stack for next activities to run, starting w/ last
newIntent = new Intent(context, portrait ? MainActivity.P.class : MainActivity.class);
newIntent.setData(getIntent().getData());
intents.add(newIntent);
startActivities(intents.toArray(new Intent[intents.size()]));
}
};
The code should check to see if the calling activity is a trusted source, then use the intent; if it isn't then a different intent is used.
However, when I publish the app on the Google Play store it says that the vulnerability still exists in this bit of code.
This is legacy code and has been working fine up to now, so I prefer not to make large change to get past this, rather just need to pass whatever static checker is being used.
I ran into this problem as well, and it seems that the confusion is caused by two separate problems, combined. First, their suggested implementation for Option 2 is incomplete due to that method being nullable. Second, they reject the entire app update, if ANY of the remaining APKs is considered vulnerable.
1.
Google confused us by continuing to reject our app updates, even though we believed we had solved the problem. However, you should pay attention to the versionCode specified in the rejection email -- because they might not be rejecting your latest app version!
In our case, we had an old (vulnerable) app version in production (say, versionCode=100) track, and a first-attempt at fixing the issue in the Beta track (versionCode=150) (see #2 below). When we released a second-attempt at fixing the issue (versionCode=200), Google still sent us the rejection email, but the email still specifically cited versionCode 150, NOT 200.
The reason is because the 150 version was in the beta track, and the 200 version went straight to Production, at 5% rollout (did not replace the Beta version). So technically the 150 version was still accessible in the play store to beta users, and that was the reason for rejecting our 200 update. Once they rejected the update due to the 150 APK being available still, the 200 update was also halted, and we had no choice but to make another updated versionCode.
Once we deactivated the 150 version in the beta track, and re-released the 200 app to production, the rejection went away and we confirmed that the newer version was being distributed to users.
2.
Separately, the reason that the first attempt (150) did not resolve the issue, is because of how we were implementing their Option 2 solution. Their solution (which you linked to above)[1]:
if (getCallingActivity().getPackageName().equals(“known”)) {
but they do not consider the fact that getCallingActivity() is nullable. So in our first attempt, we were using:
if (getCallingActivity() == null || getCallingActivity().getPackageName().equals(BuildConfig.APPLICATION_ID)
and that is still vulnerable, hence why our 150 update was rejected. The accepted solution (versionCode 200 in the above example) flipped that logic:
if (getCallingActivity() != null && getCallingActivity().getPackageName().equals(BuildConfig.APPLICATION_ID))
So once we made that change and replaced the app in the beta track, everything was accepted. You can see all currently accessible app versionCodes in the play console by going to Release Management -> App Releases. Every published version in each track will be listed there.
I've got a very weird problem and is difficult to describe so please read carefully the assumptions before the answer to avoid jumping into something I already know isn't
1 - I've got an android app which login from my server
2 - after a successful login I instantiate a Singleton API which will be shared across the activities in order to make the requests to the server
3 - Isn't possible to use the app without login
4 - in my login activity I have a very clean condition
if(APIFacade.getInstance() != null){
startActivity(new Intent(this,MainActivity.class));
finish();
}else {/*error handling*/}
5 - there is just one call to startActivity method in the whole LoginActivityclass so isn't possible to start MainActivity without check if the facade is null
6 - it isn't possible to set APIFacade.INSTANCE to null after instantiating it
But even with all these conditions sometimes users get NullPointerException on MainActivity when the app tries to make the first call to API after login
String url = APIFacade.getInstance().getProfilePicUrl(); //throws nullpointerexception on 5% of the times
APIFacade class is like this:
public class APIFacade {
private static APIFacade INSTANCE = null;
#WorkerThread
public APIFacade(Object i, final boolean preLoad) {
INSTANCE = this;
//other stuff
}
public static APIFacade getInstance() {
return INSTANCE;
}
}
I'm not able to reproduce the problem in the development environment so I just know it happens due to the crashlytics dashboard on firebase...
I believe my code has no leak to lead this situation, so the only theory I got is: Android is cleaning some variables from memory when my app goes background...
I know android naturally does it for activities, but singletons?
and if yes what can I do to solve it?
Well I found the answer myself thanks to a great article: https://medium.com/#davethomas_9528/please-dont-use-singletons-to-persist-state-on-android-7bac9bc78b29
Briefly:
Everybody says that singleston on android are attached to the application life, so will only be released if the application is killed
THIS IS TRUE
what you dont hear, is that the application can be killed by the SO without user interaction (to release memory for foreground apps) and in this scenario when the user tries to come back to your app it will restart from the last used activity and not from the launcher activity.
For the past few days i've been trying to show the online/offline status of a user.. For this i have a register activity where they register and their info gets saved in firebase and if they exit an activity i have overriden its onstop method and made the value to set to offline... but if the user suddenly loses internet connection it still shows online.. i cant change it to offline because internet is needed to make a change in the database and the use doesn't have internet... SO how do i set the database value to offline... i googled quite some stuff about this but didnt find anything... Can anyone please help me out please
My code
#Override
protected void onStart() {
super.onStart();
fetchData();
// mDatabaseReference.child("UserData").child(UID).child("Online").setValue("True");
}
#Override
protected void onStop() {
super.onStop();
fetchData();
// mDatabaseReference.child("UserData").child(UID).child("Online").setValue(false);
}
What you're trying to do is known as a presence system. The Firebase Database has a special API to allow this: onDisconnect(). When you attach a handler to onDisconnect(), the write operation you specify will be executed on the server when that server detects that the client has disconnected.
From the documentation on managing presence:
Here is a simple example of writing data upon disconnection by using the onDisconnect primitive:
DatabaseRef presenceRef = FirebaseDatabase.getInstance().getReference("disconnectmessage");
// Write a string when this client loses connection
presenceRef.onDisconnect().setValue("I disconnected!");
In your case this could be as simple as:
protected void onStart() {
super.onStart();
fetchData();
DatabaseReference onlineRef = mDatabaseReference.child("UserData").child(UID).child("Online");
onlineRef.setValue("True");
onlineRef.onDisconnect().setValue("False");
}
Note that this will work in simple cases, but will start to have problems for example when your connection toggles rapidly. In that case it may take the server longer to detect that the client disappears (since this may depends on the socket timing out) than it takes the client to reconnect, resulting in an invalid False.
To handle these situations better, check out the sample presence system in the documentation, which has more elaborate handling of edge cases.
I need to know if the user is using my application at the moment.
My idea is to make a method to make his status on in the first activity.
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_admin_page);
makemeonline();
}
But how can I know if the user didn't just close the application or move it to the background?
You can override the onPause function. In your onPause function, do something like this.
#Override
public void onPause() {
super.onPause();
makeUserIdle();
}
You can not really detect if the user is not connected to internet as I suppose makeMeOnline is calling an API to get the user status posted to some server. If you want the user to track user offline as well, then you might just consider saving the values in your sqlite database and then upload the behaviour data later to the server through another API call when the device is connected to internet.
If you integrate google analytics with your project, you can have an estimate of how many users are currently using your application in the play developer console as well.