When exactly is the NFC Service deactivated? - android

I am wondering when exactly the NFC Service is started and stopped.
The source code for android 4.0.3 seems to state that the polling is dependent on a single constant (located in NfcService.java)
/** minimum screen state that enables NFC polling (discovery) */
static final int POLLING_MODE = SCREEN_STATE_ON_UNLOCKED;
I would interpret this as "the screen light is on, therefore the nfc service is active".
BUT when the screen is locked, a NFC Tag wont be recognized, altough the screen is lit.
So I am curious: Is the NFC Service already deactivated when the lock screen appears, or is it still running but not processing the Tags?

Actually, I do not think that NFC Service is deactivated. When the screen has lower value then SCREEN_STATE_ON_UNLOCKED a device stops to ask NFC tags around. You can see this from this code:
// configure NFC-C polling
if (mScreenState >= POLLING_MODE) {
if (force || !mNfcPollingEnabled) {
Log.d(TAG, "NFC-C ON");
mNfcPollingEnabled = true;
mDeviceHost.enableDiscovery();
}
} else {
if (force || mNfcPollingEnabled) {
Log.d(TAG, "NFC-C OFF");
mNfcPollingEnabled = false;
mDeviceHost.disableDiscovery();
}
}
But NFC-EE routing is enabled util screen state is higher then SCREEN_STATE_ON_LOCKED:
// configure NFC-EE routing
if (mScreenState >= SCREEN_STATE_ON_LOCKED &&
mEeRoutingState == ROUTE_ON_WHEN_SCREEN_ON) {
if (force || !mNfceeRouteEnabled) {
Log.d(TAG, "NFC-EE ON");
mNfceeRouteEnabled = true;
mDeviceHost.doSelectSecureElement();
}
} else {
if (force || mNfceeRouteEnabled) {
Log.d(TAG, "NFC-EE OFF");
mNfceeRouteEnabled = false;
mDeviceHost.doDeselectSecureElement();
}
}
The service itself is started and stopped in other parts of this class.

See related http://forum.xda-developers.com/showthread.php?t=1712024&page=14

Related

Disable split screen mode for all apps in Android

What I Want:
Disable user to use split screen mode for any application in his phone.
What I've already done:
To disable split screen mode, I need to detect which method is called and in that method I can further add a functionality to draw a custom view over it or quickly pull down split screen window.
I'm looking into AccessibilityEvents as well, might be I need to parse and filter some keywords to get to split screen detection.
So what can be that method in which Android will tell that user has just started to use split screen mode. And how can I then quickly pull down split screen window?
You can detect when any application goes to split screen mode if you have asked AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED event when registering for accessibility service.
Possible way to detect Split screen mode:
In the onAccessibilityEvent(AccessibilityEvent event) function we need to write event.getSource().getContentDescription(); and search for "Split" or "Dismiss" or other keywords in the string, depends upon various custom roms. Whenever application comes in split screen mode, its content description is set as 'Split Whatsapp' etc. That's how we can detect when any particular application comes in split screen mode.
Possible way to block usage of split screen mode for any app:
After detecting you need to add this line in order to make it impossible for the user to utilize split screen mode. It will just dock the current application window.
performGlobalAction(AccessibilityService.GLOBAL_ACTION_TOGGLE_SPLIT_SCREEN)
There are other global events as well to perform an action like:
GLOBAL_ACTION_BACK
GLOBAL_ACTION_HOME
GLOBAL_ACTION_LOCK_SCREEN
GLOBAL_ACTION_NOTIFICATIONS
GLOBAL_ACTION_POWER_DIALOG
GLOBAL_ACTION_QUICK_SETTINGS
GLOBAL_ACTION_RECENTS
GLOBAL_ACTION_TAKE_SCREENSHOT
GLOBAL_ACTION_TOGGLE_SPLIT_SCREEN
But most suitable for this scenario is: GLOBAL_ACTION_TOGGLE_SPLIT_SCREEN
public class AppAccessibility extends AccessibilityService {
#Override
protected void onServiceConnected() {
super.onServiceConnected();
AccessibilityServiceInfo config = new AccessibilityServiceInfo();
config.eventTypes = AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED;
config.feedbackType = AccessibilityServiceInfo.FEEDBACK_GENERIC;
if (Build.VERSION.SDK_INT >= 16) {
config.flags = AccessibilityServiceInfo.FLAG_INCLUDE_NOT_IMPORTANT_VIEWS;
}
setServiceInfo(config);
}
#Override
public void onAccessibilityEvent(AccessibilityEvent event) {
if (event != null && event.getEventType() == AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED) {
if (event.getSource() != null && event.getSource().getContentDescription() != null) {
if (event.getSource().getContentDescription().toString().contains("Split")) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
performGlobalAction(AccessibilityService.GLOBAL_ACTION_TOGGLE_SPLIT_SCREEN));
}
}
}
}
}

onTagDiscovered() not called any more when nfc tag already there after updating from 4.4.4 to 5.1.1 Samsung

I had a code able to detect an already present NFC tag when I start my NFCadapter. Which is very nice since it means you don't need to move the tag to detect and read it :)
Since I update a Samsung phone to 5.1.1 form 4.4.4, this is not working any more. Moving the tag to close contact does fire onTagDiscovered() but it used to be fire instantly.
AFAIK, Google changes around NFC should not have impacted my workflow : http://developer.android.com/sdk/api_diff/21/changes.html displays only added methods. And changes from 21 to 22 does not seem to have impact nfc am I right ?
Here is my call :
this.nfcAdapter.enableReaderMode(this.activity, this, NfcAdapter.FLAG_READER_NFC_A, Bundle.EMPTY);
Any idea about why the behaviour is degraded ? Any hints to work toward ?
I plan on testing this to other devices in 5.1.1 to check if it is samsung related only or Lollipop based. Finding such devices might take some time.
Thanks.
I coded a fix tonight that solves my issue temporary.
You need a Samsung Knox licence to implement this fix (or to be root I guess).
The fix adds 2 to 4 seconds compared with my previous workflow to read and check a password against the card, which is quite significant. Thus it is only temporary. I will update with a better solution in time.
My code and Fidesmo's code both detect tag when already pressed against the phone for 4.4.4 but fails for 5.1.1. Funnily enough, if you lock/unlock the phone, the phone detects the tag and both applications (Fidesmo's and mine) receive the onTagDiscovered callback. That comes from Android "switching off" NFC when screen is off (security reasons I think). From this constatation, the fix is obvious :
Fix : stop and start NFC + set up a receiver to listen to the NFC turn on/off.
Do whatever your implementation was doing before.
IntentFilter filter = new IntentFilter("android.nfc.action.ADAPTER_STATE_CHANGED");
BroadcastReceiver receiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
Toast.makeText(Start.this, "broadcast received : "+ NfcAdapter.getDefaultAdapter(Start.this).isEnabled(), Toast.LENGTH_SHORT).show();
// My code for communication with NFC Card :
nfcCardApi= new nfcCardApi(Start.this);
nfcCardApi2= new APICardNFC(nfcCardApi);
APICardNFC.initForNFC(Start.this, nfcTypeCard);
APICardNFC.startWaitingCard();
tvInfo.setText(getResources().getString(R.string.login_pass_card));
}
};
registerReceiver(receiver, filter);
// restart NFC to try to grab the tag :
disableEnableNFC();
and disableEnableNFC() :
protected void disableEnableNFC() {
DeviceSettingsPolicy mDeviceSettings = DeviceSettingsPolicy.getInstance(context);
try {
if ( mDeviceSettings.startNFC(false)) {
if (Params.tagFgDebug && fgDebugLocal){Log.i(Params.tagGen, tagLocal + "mDeviceSettings.startNFC(false) : true NFC disable " );};
} else {
if (Params.tagFgDebug && fgDebugLocal){Log.i(Params.tagGen, tagLocal + "mDeviceSettings.startNFC(false) : false NFC disable FAILED " );};
}
if ( mDeviceSettings.startNFC(true)) {
if (Params.tagFgDebug && fgDebugLocal){Log.i(Params.tagGen, tagLocal + "mDeviceSettings.startNFC(true) : true NFC enable " );};
} else {
if (Params.tagFgDebug && fgDebugLocal){Log.i(Params.tagGen, tagLocal + "mDeviceSettings.startNFC(true) : false NFC enable FAILED " );};
}
} catch (SecurityException e) {
new TePVException(tagLocal, "disableEnableNFC", "SecurityException: " + e.getLocalizedMessage());
}
}

Detect if Android device uses navigational control

This is something I've been struggling with for quite some time. A lot of Chinese Android manufacturers create Android TV boxes that are controlled using a remote with keypad controls.
I'm looking for a definitive way of detecting if the device uses navigational controls or if it is in fact using touch screen input. Certain devices might emulate touch screen input as mouse input as well, so it's kind of tricky.
Any ideas?
Please read about input controls in the following articles:
http://developer.android.com/training/keyboard-input/index.html
http://developer.android.com/training/keyboard-input/navigation.html
http://developer.android.com/training/tv/optimizing-navigation-tv.html
To see at run-time what types of navigation a user has available, use the Configuration class.
Configuration configuration = context.getResources().getConfiguration();
if (Configuration.NAVIGATION_NONAV == configuration.navigation) {
// Device has no navigation facility other than using the touchscreen.
} else if (Configuration.NAVIGATION_DPAD == configuration.navigation) {
// Device has a directional-pad (d-pad) for navigation.
} else if (Configuration.NAVIGATION_TRACKBALL == configuration.navigation) {
// Device has a trackball for navigation.
} // ... etc
Based on Jozua's answer, I created this simple method which can be used to determine if a device uses navigation controls from a number of factors. The code is written in a way that attempts to fail early.
/**
* Determines if the device uses navigation controls as the primary navigation from a number of factors.
* #param context Application Context
* #return True if the device uses navigation controls, false otherwise.
*/
public static boolean usesNavigationControl(Context context) {
Configuration configuration = context.getResources().getConfiguration();
if (configuration.navigation == Configuration.NAVIGATION_NONAV) {
return false;
} else if (configuration.touchscreen == Configuration.TOUCHSCREEN_FINGER) {
return false;
} else if (configuration.navigation == Configuration.NAVIGATION_DPAD) {
return true;
} else if (configuration.touchscreen == Configuration.TOUCHSCREEN_NOTOUCH) {
return true;
} else if (configuration.touchscreen == Configuration.TOUCHSCREEN_UNDEFINED) {
return true;
} else if (configuration.navigationHidden == Configuration.NAVIGATIONHIDDEN_YES) {
return true;
} else if (configuration.uiMode == Configuration.UI_MODE_TYPE_TELEVISION) {
return true;
}
return false;
}
I have tested this on numerous phones, tablets, emulator configurations and Google TV. A number of devices are controlled using a remote control and a USB mouse. I haven't yet tested whether it works as expected on such devices.

Android Bluetooth Low Energy Pairing

How to pair a Bluetooth Low Energy(BLE) device with Android to read encrypted data.
Using the information in the Android BLE page, I am able to discover the device, connect to it, discover services and read un-encrypted characteristics.
When I try to read an encrypted characteristic (one that will cause iOS to show a popup asking to pair and then complete the read) I am getting an error code 5, which corresponds to Insufficient Authentication.
I am not sure how to get the device paired or how to provide the authentication information for the read to complete.
I toyed with BluetoothGattCharacteristics by trying to add descriptors, but that did not work either.
Any help is appreciated!
When you get the GATT_INSUFFICIENT_AUTHENTICATION error, the system starts the bonding process for you. In the example below I'm trying to enable notifications and indications on glucose monitor. First I'm enabling the notifications on Glucose Measurement characteristic which can cause the error to appear.
#Override
public void onDescriptorWrite(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) {
if (status == BluetoothGatt.GATT_SUCCESS) {
if (GM_CHARACTERISTIC.equals(descriptor.getCharacteristic().getUuid())) {
mCallbacks.onGlucoseMeasurementNotificationEnabled();
if (mGlucoseMeasurementContextCharacteristic != null) {
enableGlucoseMeasurementContextNotification(gatt);
} else {
enableRecordAccessControlPointIndication(gatt);
}
}
if (GM_CONTEXT_CHARACTERISTIC.equals(descriptor.getCharacteristic().getUuid())) {
mCallbacks.onGlucoseMeasurementContextNotificationEnabled();
enableRecordAccessControlPointIndication(gatt);
}
if (RACP_CHARACTERISTIC.equals(descriptor.getCharacteristic().getUuid())) {
mCallbacks.onRecordAccessControlPointIndicationsEnabled();
}
} else if (status == BluetoothGatt.GATT_INSUFFICIENT_AUTHENTICATION) {
// this is where the tricky part comes
if (gatt.getDevice().getBondState() == BluetoothDevice.BOND_NONE) {
mCallbacks.onBondingRequired();
// I'm starting the Broadcast Receiver that will listen for bonding process changes
final IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_BOND_STATE_CHANGED);
mContext.registerReceiver(mBondingBroadcastReceiver, filter);
} else {
// this situation happens when you try to connect for the second time to already bonded device
// it should never happen, in my opinion
Logger.e(TAG, "The phone is trying to read from paired device without encryption. Android Bug?");
// I don't know what to do here
// This error was found on Nexus 7 with KRT16S build of Andorid 4.4. It does not appear on Samsung S4 with Andorid 4.3.
}
} else {
mCallbacks.onError(ERROR_WRITE_DESCRIPTOR, status);
}
};
Where the mBondingBroadcastReceiver is:
private BroadcastReceiver mBondingBroadcastReceiver = new BroadcastReceiver() {
#Override
public void onReceive(final Context context, final Intent intent) {
final BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
final int bondState = intent.getIntExtra(BluetoothDevice.EXTRA_BOND_STATE, -1);
final int previousBondState = intent.getIntExtra(BluetoothDevice.EXTRA_PREVIOUS_BOND_STATE, -1);
Logger.d(TAG, "Bond state changed for: " + device.getAddress() + " new state: " + bondState + " previous: " + previousBondState);
// skip other devices
if (!device.getAddress().equals(mBluetoothGatt.getDevice().getAddress()))
return;
if (bondState == BluetoothDevice.BOND_BONDED) {
// Continue to do what you've started before
enableGlucoseMeasurementNotification(mBluetoothGatt);
mContext.unregisterReceiver(this);
mCallbacks.onBonded();
}
}
};
Remember to unregister the broadcast receiver when exiting the activity. It may have not been unregistered by the receicver itself.
You might need to check the Kernel smp.c file, which method of paring it invoke for paring. 1) passkey 2)Just work or etc . i guess if it will be able to invoke MIMT and passkey level of security , there will not be any authentication issue. Make sure all flags is set to invoke the SMP passkey methods. track by putting some print in smp.c file.
A solution which works in ICS : with btmgmt tool in android and hooking it in encryption APIs. with passkey or any other methods. it works. You might need to add the passkey APIs in btmgmt from latest bluez code.
i think new android 4.4 provide pairing method. same problem already i am facing so wait for update and hope over problem solved createBond() method .
http://developer.android.com/reference/android/bluetooth/BluetoothDevice.html#setPairingConfirmation%28boolean%29

Camera.Parameters.FLASH_MODE_TORCH replacement for Android 2.1

I am trying to write an app that requires the LED flash to go into torch mode. The problem is, Android 2.1 does not support this mode and therefore I cannot support the platform yet. Wouldn't be an issue, but I am writing it for my fiance and her Epic 4G only has 2.1 right now. I found some code samples that use some undocumented API calls and therefore work on the Motorola Droid and such, but they do not work on the Epic. Does anyone have some suggestions on where to look to find code that should help me get this working?
I'm finding that torch mode is generally working fine on 2.1 but I had the same problem with the Samsung Epic and found a hack around it.
Looking at the params returned by Camera.getParameters() when run on the Samsung Epic, I noticed that the flash-modes it claims to support are: flash-mode-values=off,on,auto;
torch-mode is not listed, implying it's not supported.
However, I found that this model would still accept that mode and WOULD turn the LED on! The bad news was that when later setting the flash-mode back to auto or off left the LED still lit! It will not turn off until you call Camera.release().
I guess that's why Samsung dont include it in the list of supported!?!
So...the method I use to toggle torch in a CameraHelper class is...
/***
* Attempts to set camera flash torch/flashlight mode on/off
* #param isOn true = on, false = off
* #return boolean whether or not we were able to set it
*/
public boolean setFlashlight(boolean isOn)
{
if (mCamera == null)
{
return false;
}
Camera.Parameters params = mCamera.getParameters();
String value;
if (isOn) // we are being ask to turn it on
{
value = Camera.Parameters.FLASH_MODE_TORCH;
}
else // we are being asked to turn it off
{
value = Camera.Parameters.FLASH_MODE_AUTO;
}
try{
params.setFlashMode(value);
mCamera.setParameters(params);
String nowMode = mCamera.getParameters().getFlashMode();
if (isOn && nowMode.equals(Camera.Parameters.FLASH_MODE_TORCH))
{
return true;
}
if (! isOn && nowMode.equals(Camera.Parameters.FLASH_MODE_AUTO))
{
return true;
}
return false;
}
catch (Exception ex)
{
MyLog.e(mLOG_TAG, this.getClass().getSimpleName() + " error setting flash mode to: "+ value + " " + ex.toString());
}
}
The activities that use this call it as follows...
private void toggleFlashLight()
{
mIsFlashlightOn = ! mIsFlashlightOn;
/**
* hack to fix an issue where the Samsung Galaxy will turn torch on,
* even though it says it doesnt support torch mode,
* but then will NOT turn it off via this param.
*/
if (! mIsFlashlightOn && Build.MANUFACTURER.equalsIgnoreCase("Samsung"))
{
this.releaseCameraResources();
this.initCamera();
}
else
{
boolean result = mCamHelper.setFlashlight(mIsFlashlightOn);
if (! result)
{
alertFlashlightNotSupported();
}
}
}
The magic that makes this work in releaseCameraResources() is that it calls Camera.release()....and then I have to reinitialize all my camera stuff for Samsung devices.
Not pretty but seems to be working for plenty of users.
Note that I do have a report of torch mode not working at all with this code on Nexus one but have been able to dig into it. It definitely works on HTC EVO and Samsung Epic.
Hope this helps.
In my case for Samsung devices I needed to set focus mode to infinity and it started to work
params.setFocusMode(Camera.Parameters.FOCUS_MODE_INFINITY);
mCamera.setParameters(params);
mCamera.startPreview();

Categories

Resources