A bit of a weird issue when using the fingerprint scanner in Android 6.0 (Marshmallow) that I am stuck with and can't figure out.
I have searched all over but can only see things related to hardware defects.
The application accepts, encrypts, decrypts and validates fingerprints just fine, however it only allows 5 attempts before it for some reason stops working. (More on that below)
I have setup the application to allow the user four scan attempts before implementing a security lockout timer, however if I intentionally fail to authenticate 4 times. Then I wait to lockout period of 5 minutes and come back I can only scan my finger once, after that the fingerprint appears to stop listening until I force quit the application from Applications Manager?
It then accepts fingerprints again.
Code for authenticationFailed callback:
#Override
public void onAuthenticationFailed() {
authenticationDialog.dismiss();
cancellationSignal.cancel();
//Add one to the number of attempts taken
attemptCount += 1;
if (attemptCount < maxAttempAllowance) {
AlertDialog.Builder message = new AlertDialog.Builder(appContext);
message.setTitle("Authentication Failed");
message.setMessage("The finger you scanned is not registered in your devices settings or your device failed to identify you.");
message.setPositiveButton("Try Again", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
showAuthenticationDialog();
startAuth(manager, cryptoObject);
}
});
message.setIcon(R.drawable.cross_flat);
message.setCancelable(false);
message.show();
}
else {
AlertDialog.Builder message = new AlertDialog.Builder(appContext);
message.setTitle("Authentication Failed");
message.setMessage("You have exceeded the maximum login attempts allowed. Try again in 5 minutes.");
message.setIcon(R.drawable.cross_flat);
message.setCancelable(false);
message.show();
setSecurityBanTimer();
}
}
Even without the lockout security code the scanner still only accepts 5 prints.
I have found at that the API forces the security to have a 30 second gap between 5th and further attempts.
This means that the scanner will be unresponsive after the 5th attempt if the security of the application sets lockout at 4.
Documentation:
Device implementations with a secure lock screen SHOULD include a fingerprint sensor. If a device implementation includes a fingerprint sensor and has a corresponding API for third-party developers, it:
MUST rate limit attempts for at least 30 seconds after 5 false trials for fingerprint verification.
Find information here.
Related
I am developing a keyboard app for Android in Java and I want to be able to send inputs as if my application was a virtual game controller.
Example:
The inputs I want to send are among the following default buttons (DPAD_UP, BUTTON_A, etc)
Image source: https://developer.android.com/training/game-controllers/controller-input
I see a lot of resources regarding Event listeners and how to handle gamepad or key inputs (as if I was a game receiving inputs), but I haven't found anything on the "server side", on how to actually send these inputs from one app (my keyboard) to another (the game).
I have already registered my app as a keyboard app, and I am able to send normal key inputs (such as letters) to compose a text. To to that I am overriding the function onKey() from KeyboardView.OnKeyboardActionListener.
Sources: https://developer.android.com/reference/android/inputmethodservice/KeyboardView.OnKeyboardActionListener#onKey(int,%20int[])
https://www.androidauthority.com/lets-build-custom-keyboard-android-832362/
#Override
public void onKey(int primaryCode, int[] keyCodes) {
InputConnection inputConnection = getCurrentInputConnection();
if (inputConnection != null) {
switch(primaryCode) {
case Keyboard.KEYCODE_DELETE :
CharSequence selectedText = inputConnection.getSelectedText(0);
if (TextUtils.isEmpty(selectedText)) {
inputConnection.deleteSurroundingText(1, 0);
} else {
inputConnection.commitText("", 1);
}
case Keyboard.KEYCODE_SHIFT:
caps = !caps;
keyboard.setShifted(caps);
keyboardView.invalidateAllKeys();
break;
case Keyboard.KEYCODE_DONE:
inputConnection.sendKeyEvent(new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_ENTER));
break;
default :
char code = (char) primaryCode;
if(Character.isLetter(code) && caps){
code = Character.toUpperCase(code);
}
inputConnection.commitText(String.valueOf(code), 1);
}
}
}
However, I don't see how this could help me send the gamepad Keycodes.
So my question is: what is the correct way to send the game controller keypresses from my app to another app (the game)? I want to be able to press a virtual button on my app (emulating a BUTTON_A [keycode 96] for example), and send this key input to the game.
Important: my app cannot have root privileges or be signed as a system app. So that is why I am trying the keyboard approach, so I can be registered as a virtual keyboard on the device that I want to control and then be able to send key inputs from inside my app to another app running on the same device (the game that supports a game controller).
Thank you in advance.
I am currently working on an Android app in which I want to use Google Play Games services (Achievements, Leaderboards, ...). After many iterations I finally got the code working to show the Google Play Games Login promt. The problem is now that after the user signs in it takes a while and then throws error code 4 with error message being empty. After doing a lot of research nothing really helped me solving this problem.
I have tried starting it directly out of Android Studio, installing the app manually or over Google Play, all on multiple devices, nothing worked.
Here's some code if required:
private static GoogleSignInClient mGoogleSignInClient;
...
#Override
protected void onCreate(Bundle savedInstanceState) {
...
mGoogleSignInClient = GoogleSignIn.getClient(this, new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_GAMES_SIGN_IN).requestIdToken(getResources().getString(R.string.app_id)).build());
signInSilently(); // Can't be tested yet.
// isSignedIn() and loginDeclined are both false
if(!isSignedIn() && !loginDeclined) startSignInIntent();
}
...
private void startSignInIntent() {
startActivityForResult(mGoogleSignInClient.getSignInIntent(), RC_SIGN_IN);
loginDeclined = true;
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent intent) {
super.onActivityResult(requestCode, resultCode, intent);
// resultCode = 0
if (requestCode == RC_SIGN_IN) {
Task<GoogleSignInAccount> task =
GoogleSignIn.getSignedInAccountFromIntent(intent);
try {
GoogleSignInAccount account = task.getResult(ApiException.class);
// Now this never happens :(
System.out.println("SUCCESS!");
} catch (ApiException apiException) {
System.out.println(apiException.getStatusCode() + " + " + apiException.getMessage());
// statusCode is 4, message is "4: "
String message = apiException.getMessage();
if (message == null || message.isEmpty()) {
message = "Error signing in to Google Play Games";
}
new android.app.AlertDialog.Builder(this)
.setMessage(message)
.setNeutralButton(android.R.string.ok, null)
.show();
}
}
}
Make sure that you use the SHA1 key.
The command "keytool -list -keystore [path to debug keystore]" may display a SHA-256 key.
To get your SHA1 key you can follow these steps:
Open your project
Click on "Gradle" (on the right side)
Choose your module
Tasks -> android -> (double click) signingReport
image: get your SHA1 key
After searching on the internet for hours and checking every step from the troubleshooting section in the google play game services documentation (https://developers.google.com/games/services/android/troubleshooting), I filled out the "OAuth Consent Screen" form and it finally worked.
Log in to the Google Play Console
Go to Game Services
Go to your game
On the Game Details page scroll all the way down to the linked API console project
Click the link to the linked API console project
Click "OAuth Conset Screen" in the left side bar
Choose external
Fill out the form and upload an icon
Send for verification
After that my Google Play Game Services Sign In worked instantly.
Please check the following details for GPG Sign in issues:
Make sure that you have followed the instructions to create your client IDs and configure the games services.
Your meta data Tag in manifest should match with your application's numeric ID, and it should only contain the numbers. Also double check your package name. Do not use the sample app package name. Use your own.
The certificate with which you are signing your game should match the certificate fingerprint associated to your client ID.
The last important thing, Check that test accounts are enabled. I keep forgetting this step.
Make sure that the fingerprint from App signing certificate matches with the linked apps from Game services. You can also verify these details by navigating to your Google API console -> Select your app -> Credentials -> OAuth 2.0 client IDs.
The other thing I noticed that, if the app is released, then you need to install the app from the Play Store for these credentials to work. If the app is not yet released, then make sure you are using the debug fingerprint and that matches in your Games services (Debug fingerprint).
As far as you have these fingerprints in place, you should be fine. If you are still having issues, I would recommend to go through the code lab to get step by step help on how to to extend an existing Unity game to run on an Android device and integrate Play Game Services.
https://codelabs.developers.google.com/codelabs/playservices_unity/index.html?index=..%2F..%2Findex#0
Or here are the sample apps to help with quick test -
https://github.com/playgameservices/android-basic-samples.
You can also help us with the logcat to better understand the issue.
Recently, I faced the problem when i was trying to write the user data on his drive using the saved game api. And i figured out the problem. Below are my observation hope it will help in general scenario:
You can test the play games api in debug build by adding testers in your play console.
If you want to test on signed apk, then you need to generate the SHA1 key by using your "app.keystore" keystore file and add the android app with this SHA1 key in play game services particular for that app. Now you would be able to get the expected result.(It was the problem in my case)
If you want to store the data on user drive, then you need to enable "saved games" api in play game services.
In my case everything looked fine but get error code, then i check Google Play Console> Play Game Service and publish the changes. The key is publishing things that i made.
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.
I am new to bluetooth programming, so please keep that in mind.
I am trying to connect to a pulse sensor from a desktop pc, specifically the Zephyr HxM BT. I am not using any device specific drivers, the Java bluetooth library I'm using is Bluecove, and my bluetooth stack is BlueSoleil.
From my understanding, the way I proceed is
1) Scan for BT devices
public void startSearch() throws BluetoothStateException{
System.out.println("Inquiry started");
localdevice.getDiscoveryAgent().startInquiry(DiscoveryAgent.GIAC, this);
}
This works fine, it discovers my pulse belt and calls
public void deviceDiscovered(RemoteDevice arg0, DeviceClass arg1)
2) Search a device for services
Once a device has been discovered, it should be added to the DiscoveryAgent's list of cached devices, this is my first problem as the cache (and preknown devices) is always empty even though I've discovered my belt.
So the way that I do this now is to either keep my own list of devices, or simply start a service search directly from deviceDiscovered.
I am still a bit unsure if I'm using the correct parameters, but from reading the BT device manual and the javax.bluetooth documentation on DiscoveryAgent.searchServices:
public int searchServices(int[] attrSet,
UUID[] uuidSet,
RemoteDevice btDev,
DiscoveryListener discListener)
throws BluetoothStateException
My code:
public void searchServices(RemoteDevice device){
UUID[] uuidSet = new UUID[1];
uuidSet[0]=new UUID("1101",false); //Serial Port
System.out.println("Searching for services on " + device.getBluetoothAddress() );
try{
agent.searchServices(null,uuidSet, device,this);}
catch (BluetoothStateException e){
System.out.println("BluetoothStateException caught.");
}
}
I've set the attributes parameter to null, because the documentation states that this will have it search for services with the default attributes, however I've also tried to use only ServiceID (0x0003) as attribute with no luck.
This is where I'm stuck, I pass the correct BT device into the function, and it starts searching but never give me any results, it just searches forever for all I know, no exception, no calls to
public void servicesDiscovered(int arg0, ServiceRecord[] arg1)
or
public void serviceSearchCompleted(int arg0, int arg1)
So I guess my questions are:
- Am I doing something wrong? Any suggestions?
- What are the other approaches to connecting to a BT device, and what
information do I have to know about the device to do that?
Here is some information that I think is relevant from the device manual:
The following steps have to be undertaken to connect to a HxM device.
1) Activate the Bluetooth service of the device/computer wanting to connect to the HxM
2) Scan for Bluetooth devices in range
3) Pair with the HxM device found in range
4) Discover Services of Paired HxM
5) Connect to serial port of HxM device
The diagram above shows that the Bluetooth HxM typically communicates with a mobile device over the Bluetooth
link. The HxM only supports one link at a time and uses the Bluetooth SPP (Serial Port Profile) to communicate
with other devices with the following low-level protocol:
• 115,200 baud
• 8 data bits
• 1 stop bit
• No parity
Any suggestions are very much appreciated
edit: I just want to add that I'm testing the code with a console input loop, so the program is not immediately terminated after calling searchServices, it should have time to complete unless I'm misunderstanding async tasks
I just wanted to update this and say that I found the problem, it seems that I had to use a short UUID instead of a long. I should have tried both of these options before I deemed myself stuck, but I didn't think it would make any difference.
I am working on an GWT-ext application.
In this application I managed client side session. For this I write below code:
To manage the session:
import com.google.gwt.user.client.Timer;
public class ClientTimers {
private static final Timer SESSION_MAY_HAVE_EXPIRED_TIMER = new Timer() {
#Override
public void run() {
// Warn the user, that the session may have expired.
// You could then show a login dialog, etc...
}
};
public static void renewSessionTimer() {
// First cancel the previous timer
SESSION_MAY_HAVE_EXPIRED_TIMER.cancel();
// Schedule again in 5 minutes (maybe make that configurable?)
// Actually, let's subtract 10 seconds from that, because our timer
// won't be synchronized perfectly with the server's timer.
SESSION_MAY_HAVE_EXPIRED_TIMER.schedule(5 * 60 * 1000 - 10000);
}
}
To get the user activity:
Ext.get("pagePanel").addListener("click", new EventCallback() {
#Override
public void execute(EventObject e) {
//MessageBox.alert("On Mouse Click");
});
Ext.get("pagePanel").addListener("keydown", new EventCallback() {
#Override
public void execute(EventObject e) { //
//MessageBox.alert("On Key Press Click");
}
});
This code is working fine but my issues :
This code will do log out automatically as the time out occurs.For my code I want that on click or key down it should do logout. Case is like this:If user is logged in and time to log out is 5 min.User don't do any activity on the screen than right now as per the above code it will log out automatically as the 5 min complete.
Now my requirement is that if user logged in and it doesn't do any thing for 5 mins.It should not do any logged out automatically.Instead of logging out on completion of 5 min,If user do click or key down on 6 min then it should do the log out process.
Basically the log out process as the timer exceed the specified time should be done on the user activity, not automatically.
In the Timer, increment a variable for each second.
And when user click on any button after 5 minutes or on 6th minute than check the counter variable and if the variable is greater than 6 than you can use Window.Location.reload(); to logout or reload().
I think the thing you are searchin for is:
Window.Location.reload();
Fire it every few secons with a timer, so the user always apper to be active.
(Btw I have that from Window close issues in gwt -ext )
Install a JavaScript event handler on an invisible div that covers the whole area. If it gets an event, send an AJAX request to the server.
The server can then do whatever it needs to do. On the client side, you can wait for a reply from the AJAX request and display "You have been logged out".
There is one drawback of this approach: Objects stored in the session will be kept alive for too long. So even if the user never logs out and just walks away (or his browser crashes), the session will stay alive.
After a couple of days, so many dead sessions will accumulate that your server will crash.
So the better solution is to auto logout the user as you do already and install an AJAX event handler as described above to display a message when the user returns to the browser.
This way, your server can clean up dead sessions and the user gets a message when he can read it (when he is in front of the screen).
Note that you can't differentiate between the user and the cleaning crew hitting the mouse.