Programmatically disable the screen on/off magnetic sensor on Android - java

Several Android devices famously the Nexus series have a magnetic sensor that is NOT the android.hardware.Sensor.TYPE_MAGNETIC_FIELD used exclusively to turn the screen ON/OFF automatically using phone cases that have a small magnet inside them.
On my application, I'm using magnet detection using android.hardware.Sensor.TYPE_MAGNETIC_FIELD and the SensorManager to detect user touches the phone in a case with some magnets inside.
The code works without issues, the problem is that it's extremely easy on those devices to accidentally trigger the screen ON/OFF sensor thou, turning off the screen.
I've tried:
android:keepScreenOn="true" on the XML
using the permission android.permission.WAKE_LOCK and acquiring a wake-lock via PowerManager.
Both without success.
Is there a way to temporarily disable this sensor while my activity is resumed?

The keepScreenOn = true in manifest also doesn't work here as the action of hall effect sensor is same as pressing power button.
Here, I offer a work-around that I have tested. In this approach you display your activity regardless of hall-effect sensor locking the device and turning of the display.
Before beginning the unlocking action
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON |
WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD |
WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED |
WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON);
credits for above code - https://stackoverflow.com/a/45951927/9640177
Also make sure to add Permissions
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
<uses-permission android:name="android.permission.WAKE_LOCK" />
Setting these flags will make sure that your window will be visible above lockscreen.
Now, listen for ACTION_SCREEN_OFF intent. To do this add a broadcast receiver that listens for this intent broadcasted by the system. You need to register the receiver locally. (stackoverflow.com/a/9478013/9640177)
in manifest
<receiver android:name=".receiver">
<intent-filter>
<action android:name="android.intent.action.SCREEN_OFF"/>
</intent-filter>
</receiver>
Receiver class
public class receiver extends BroadcastReceiver {
MyActivity activity;
receiver(MyActivity activity){
this.activity = activity;
}
#Override
public void onReceive(final Context context, Intent intent) {
activity.turnOnScreen();
}
}
Inside activity
// register receiver
...
IntentFilter screenStateFilter = new IntentFilter();
screenStateFilter.addAction(Intent.ACTION_SCREEN_OFF);
receiver r = new receiver(MyActivity.this);
registerReceiver(r, screenStateFilter);
...
// function to turn on display
public void turnOnScreen(){
PowerManager powerManager = (PowerManager) getSystemService(Context.POWER_SERVICE);
PowerManager.WakeLock wakeLock = powerManager.newWakeLock(PowerManager.FULL_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP, "my:Tag");
wakeLock.acquire();
wakeLock.release();
}
credit - https://stackoverflow.com/a/44706632/9640177
This will turn the display on.
Don't forget to remove these flags after your activity has done the job and does not require to be in forefront.
getWindow().removeFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON |
WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD |
WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED |
WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON);
This will make your window disappear from lock-screen and make the application function normally.
Hope this helps.

the most pragmatic solution to the problem might be ...
to disable the smart cover feature physically rather than by software.
eg. take a razorblade and tweezers and then remove the magnet.
... or simply get another cover without a magnet.
alternatively, file a bug against drivers/input/lid.c.

Related

my app doesn't send any notifications when it's not running (killed)

I have a reminder app that sends a notification according to the time of the item in the listview, the problem is that whenever my phone is rebooted or the app is killed, the app doesn't send any notification.
Note: The app is offline and local, it doesn't use internet connection, I don't use FCM or and online services for this app.
Thank you so much for your time.
Update:
I'm using a thread that searches for data in the local database, If there are any changes in time in the database compared to the current time, the notification should show, but the notification only shows when the app is running, but when the app is killed it doesn't show.
The app needs to run on android 5+,
You can use Broadcast receiver in order to be notified when Boot Completes. And again start the required services of your app.
For reference, have a look here.
This is because when you are killing the app, the onDestroy method gets called. When it's killed, you app is not doing anything. For this you would need a broadcast receiver.
How to implement broadcast receiver?
Create a java class named TimeBradcastReceiver.java.
Paste this code in the class
public class TimeBradcastReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
String dateString = Calendar.getInstance().get(Calendar.HOUR) + ":" + Calendar.getInstance().get(Calendar.MINUTE);
String hourString = Calendar.getInstance().get(Calendar.HOUR);
String minutesString = Calendar.getInstance().get(Calendar.MINUTE;
Log.d("MyBradcastReceiver","i have recieved - " + dateString);
}
}
Once you have implemented this code, you need to add this to you manifest inside the application tag.
<receiver android:name="com.chatverse.free.TimeBroadcastReceiver"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.TIME_TICK"/>
</intent-filter>
</receiver>
Add this code to your activity which opens the first.
IntentFilter mTime = new IntentFilter(Intent.ACTION_TIME_TICK);
registerReceiver(new TimeBradcastReceiver(), mTime);
Now you can do the comparison of the dates and hours and show the notification.
Note - This receiver will update only when a minute has changed.

Equalizing the audio of another app - how to?

i need to make a Equalizer for Android.
El audio session ID 0 is deprecated.
Is there a way to get the current audio session ID?
I want to equalize from my app the sound of other apps.
In Google play there are other apps that use the "compatibility mode". but i do not know how they do it. For example, the app detects that spotify is playing, the session is selected and it can equalized.
Does anyone know how do this?
Thanks.
Example applications:
https://play.google.com/store/apps/details?id=com.devdnua.equalizer.free
https://play.google.com/store/apps/details?id=devdnua.equalizerp.free
According to Android, you can use ACTION_OPEN_AUDIO_EFFECT_CONTROL_SESSION to receive the id of a playing audio session:
Intent to signal to the effect control application or service that a new audio session is opened and requires audio effects to be applied.
I tried adding the constant (and many others) in the manifest, but it only worked for music apps such as Spotify and Youtube Music:
<receiver android:name=".receivers.AudioSessionReceiver">
<intent-filter>
<action android:name="android.media.action.OPEN_AUDIO_EFFECT_CONTROL_SESSION"/>
</intent-filter>
</receiver>
Then, you can use the id to create an equalizer attached to the session id.
public class AudioSessionReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
int id = intent.getIntExtra(Equalizer.EXTRA_AUDIO_SESSION, -1);
String packageName = intent.getStringExtra(Equalizer.EXTRA_PACKAGE_NAME);
}
}
When I play my own media file (with my own test app), there are equalizer apps that still work on it even though I didn't broadcast the session id of my media player. So there must be a solution involving a Service that doesn't rely on Broadcast Receivers.

Wake up screen and show activity from service

I have an IntentService running background and listening incoming TCP messages. When a desired message has been received, the device should wake up and MainActivity be on top.
I can start a new MainActivity and wake up the device, but then I have many instances of it. The best solution would be sending a broadcast message to the MainActivity, but then I cannot wake up the screen.
I have these permissions set:
<uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
I have this in my onResume()
final Window win = getWindow();
win.addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED |
WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD |
WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON |
WindowManager.LayoutParams.FLAG_ALLOW_LOCK_WHILE_SCREEN_ON);
I can call even my onResume() function, but the screen is black. When I set MainActivity as singleTop, starting new MainActivity keeps the screen black.
Any idea?

How to pause onCreate until boot completed?

I host widgets in my app and it seems, that if i start my app before booting of the device is completed, widgets cannot be created properly. Widgets then seem to be not loaded completely or not initialized/updated correctly. For instance: BatteryBotIndicator-Widget, which shows the battery status in percentage, shows a value of "XX" instead of some number like "70%". If i then restart my app and try to recreate the widget with:
AppWidgetProviderInfo appWidgetInfo = mAppWidgetManager.getAppWidgetInfo(appWidgetId);
it gives me null for appWidgetInfo (i fetch appWidgetId from SQLite database). And widget cannot be recreated.
It is kind of difficult to debug the real cause in this situation to find out what is exactly causing this (Starting Debugger at the right time). I assume the AppWidgetManager is not ready yet or something.
What i can say for sure: If i wait until i receive the broadcast-event BOOT_COMPLETED all widgets are created properly.
So how can i pause the execution of onCreate until booting is completed?
I can think of putting the thread to sleep in a while loop until the BroadcastReceiver (BOOT_COMPLETED) is setting a bool-variable in application-data to true. But i dont want to wait for this event always at starting of my app, as you can imagine ;)
if i start my app before booting of the device is completed, widgets cannot be created properly.
please explain more what exactly do you mean when you say - "not properly" . this might be relevant to understand if you're widget really depends on something related to the boot.
I can think of putting the thread to sleep in a while loop until the BroadcastReceiver (BOOT_COMPLETED) is setting a bool-variable in application-data to true
very bad idea.. also from performances and design reasons
instead, why not simply register to boot complete broadcast from the manifest, and when you recevice it - simply send the relevant broadcast to update your widget? AppWidgetProvider is already extends BroadcastReceiver, so you can simply add it intent filter for boot complete broadcast.
this is how to add intent filter to boot complete:
<receiver android:name="MyWidgetProvider" >
<intent-filter >
<action android:name="android.appwidget.action.APPWIDGET_UPDATE"/>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
<meta-data
...
</receiver>
and this is how to react to it from the widget provider implementation:
#Override
public void onReceive(Context context, Intent intent) {
if(intent.getAction().equals("android.intent.action.BOOT_COMPLETED")){
doTheUpdateHereExactlyLikeHowYouUpdateItFromAnywhereElse();
} else {
super.onReceive(context,intent);
}
}
for more information - follow this tutorial :https://laaptu.wordpress.com/2013/08/12/android-update-app-widget-with-listview-after-phone-reboot/

Using Power Manager

My app sets an alarm. While waiting for the alarm my phone closes the screen. When the alarm sounds the screen is dark so I press the power key and the screen lights up but I now have to touch the Lock button to access the app interface. I would prefer that the Lock has been disposed off when the user responds to the alarm so I tried to use the power manager. The alarm receiver starts a new activity so I initialised the power manager in the onCreate for this activity. However this causes a force close error. I call the power manager as follows
PowerManager pm = (PowerManager)cText.getSystemService(Context.POWER_SERVICE);
PowerManager.WakeLock wl = pm.newWakeLock(PowerManager.FULL_WAKE_LOCK , TAG);
wl.acquire();
Any suggestions please.
Did add the uses permisson for power mananger in your manifest?
Since the person asking the question states that he "has to touch the lock" button I assume that he is speaking about the Key Guard. (Pattern, Pin etc). You cannot use the PowerManager API to disable this. Instead you should diable the KeyGuard
KeyguardManager keyguardManager =
(KeyguardManager) getSystemService(Activity.KEYGUARD_SERVICE);
KeyguardManager.KeyguardLock lock =
keyguardManager.newKeyguardLock(KEYGUARD_SERVICE);
lock.disableKeyguard();
To My knowledge, this is the correct way to disable the Screen Lock.
You also need this Permission
<uses-permission android:name="android.permission.DISABLE_KEYGUARD"/>
You can take wl in Application context so once its initlize and set back to that and after that when you release that you will set null and check that it again if its null than init again other wise take it as it is.

Categories