Im developping app for tablets, its a car navigation.
What I need to do is - if the driver turns on car the tablet turns on screen, if the car is shut down display is off.
My first thought is to keep tablet plugged to the car charger and if the charging is detected turn on display. If the charging is not detected turn off display.
App would run in KIOSK mode. What would be the best approach to detect charging status while screen is off ?
It's pretty simple.
First you need to listen for charging state changes. It can be done by:
//Create receiver
BroadcastReceiver powerChangeReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if(Intent.ACTION_POWER_CONNECTED.equals(action)){
turnScreenOn();
} else if(Intent.ACTION_POWER_DISCONNECTED.equals(action)){
turnScreenOff();
}
}
};
//Register receiver
IntentFilter i = new IntentFilter();
i.addAction(Intent.ACTION_POWER_CONNECTED);
i.addAction(Intent.ACTION_POWER_DISCONNECTED);
registerReceiver(powerChangeReceiver, i);
and now all you need to do is to implement turnScreenOn() and turnScreenOff() methods:
public void turnScreenOn(){
runOnUiThread(() -> {
PowerManager pm = (PowerManager) getApplicationContext().getSystemService(POWER_SERVICE);
#SuppressWarnings("deprecation")
PowerManager.WakeLock wl = pm.newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK |
PowerManager.ACQUIRE_CAUSES_WAKEUP, "example:tag");
wl.acquire();
});
}
public void turnScreenOff(){
if(policyManager.isDeviceOwnerApp(getPackageName())) {
runOnUiThread(() -> {
policyManager.lockNow();
});
}
}
and don't forget to add WAKE_LOCK permission to your Manifest:
<uses-permission android:name="android.permission.WAKE_LOCK" />
Hope it helps!
Related
I am a complete novice in Java and Android. I am trying to create a test app to listen for BLE and BT devices nearby. I have another device where I wrote some logic to broadcast its BLE beacons. I verified it using a playstore app. Now I am trying to write my own app on Android.
I have been reading the Android developer pages for guidance. I have literally followed every step of the following pages
https://developer.android.com/guide/topics/connectivity/bluetooth/setup
https://developer.android.com/guide/topics/connectivity/bluetooth/permissions
https://developer.android.com/guide/topics/connectivity/bluetooth/find-bluetooth-devices
https://developer.android.com/guide/topics/connectivity/bluetooth/find-ble-devices
Also, Note that I have used BARE MINIMUM CODE from the Android Developers page So here is what I have done.
1. First off I have added my permissions under AndroidManifest
Note1 : I am deploying this app to My phone running Android 11
Note2 : All this code is written inside MainActivity. I have not created any other activity class
<uses-permission android:name="android.permission.BLUETOOTH" android:maxSdkVersion="30" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" android:maxSdkVersion="30" />
<uses-permission android:name="android.permission.BLUETOOTH_SCAN" />
<uses-permission android:name="android.permission.BLUETOOTH_ADVERTISE" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
2. Next I check if my BT is enabled.
if (bluetoothAdapter == null) {
blefinder.append("\nDEVICE DOES NOT SUPPORT BLUETOOTH");
}
else {
blefinder.append("\nDEVICE SUPPORTS BLUETOOTH");
}
I get the success message that BT is of course enabled
3. Next I check if my device supports BLE
if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) {
blefinder.append("\nBLE NOT SUPPORTED ON THIS DEVICE : ");
finish();
}
else{
blefinder.append("\nBLE IS SUPPORTED ON THIS DEVICE : ");
}
I get the message that BLE is supported
4. Next I list my already paired/bonded devices
For this I call ListPairedAndBondedDevices(); in onCreate() itself right after the above steps. Function Definition Below.
private void ListPairedAndBondedDevices(){
#SuppressLint("MissingPermission") Set<BluetoothDevice> pairedDevices = bluetoothAdapter.getBondedDevices();
if (pairedDevices.size() > 0) {
// There are paired devices. Get the name and address of each paired device.
blefinder.append("\nPAIRED/BONDED DEVICES");
for (BluetoothDevice device : pairedDevices) {
blefinder.append("\n" + device.getName() + " | " + device.getAddress());
}
}
}
This also works like a charm and prints out my paired devices. The next 2 parts is where I face the problem.
5. The Problem Step | Part 1:
Here I register a Broadcast receiver to discover all BT devices in the vicinity. I've unbonded my BT headphones and kept it in pairing mode to verify this.
ListPairedAndBondedDevices(); // From previous code snippet
IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND); // New code statement
registerReceiver(BTReceiver, filter);// New code statement
Broadcast Receiver implementation
private final BroadcastReceiver BTReceiver = new BroadcastReceiver() {
#SuppressLint("MissingPermission")
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (BluetoothDevice.ACTION_FOUND.equals(action)) {
// Discovery has found a device. Get the BluetoothDevice
// object and its info from the Intent.
BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
blefinder.append("\n" + device.getName() + " | " + device.getAddress());
}
}
};
So This part didn't Work :(
If you see above, I am registering the BTReceiver in onCreate right after listing the already paired devices (by calling ListPairedAndBondedDevices()).
When I ran the debugger, this broadcast receiver never gets called.
6. The Problem Step | Part 2:
Right after this I try to scan for BLE Devices as well by callin scanLeDevice()
ListPairedAndBondedDevices(); // From previous snippet
IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND); // From previous snippet
registerReceiver(BTReceiver, filter);// From previous snippet
scanLeDevice(); // ---------------->>> CALLING THIS FUNCTION TO SCAN FOR BLE DEVICES
Implementation of scanLeDevice()
private void scanLeDevice() {
if (!scanning) {
// Stops scanning after a predefined scan period.
handler.postDelayed(new Runnable() {
#Override
public void run() {
scanning = false;
bluetoothLeScanner.stopScan(leScanCallback);
blefinder.append("\nSTOPPING BLE SCAN... TIMEOUT REACHED");
}
}, SCAN_PERIOD);
scanning = true;
bluetoothLeScanner.startScan(leScanCallback);
} else {
scanning = false;
bluetoothLeScanner.stopScan(leScanCallback);
blefinder.append("\nSTOPPING BLE SCAN");
}
}
Unfortunately this also fails. The debugger tells me that this part of the code is getting called.
And after 30 seconds of SCAN_PERIOD (The TIMEOUT that I've set), I get the message that the scanning has stopped (STOPPING BLE SCAN)
Now I have implemented the leScanCallback as well (i.e the Device Scan Callback)
private ScanCallback leScanCallback =
new ScanCallback() {
#Override
public void onScanResult(int callbackType, ScanResult result) {
super.onScanResult(callbackType, result);
blefinder.append("SOMETHING GOT SCANNED?");
blefinder.append("\n"+result.getDevice().toString());
// leDeviceListAdapter.addDevice(result.getDevice());
// leDeviceListAdapter.notifyDataSetChanged();
}
};
Notice that I am not using a ListAdapter since I have no idea about that concept. Hence for starters I am just trying to dump the results in a TextView represented by blefinder . This blefinder prints all the other texts so there is nothing wrong with that TextView variable. When I ran using the, debugger, it is not entering into the leScanCallback piece of code definition at all, even after 30 seconds, after scanLeDevice() function is executed.
I am a little lost here. Is there something I may be missing or doing wrong. It is supposed to be a simple, list the ble/bt devices around my vicinity.
I am happy to share any further information if I have missed. Just let me know in the comments.
Assuming you've done with the permissions that I've mentioned in the comments, we can implement a clean bluetooth LE scanner object and then use it in the UI.
First we implement a result consumer interface in order to deliver the results to the consumers which call the BleScanner.scan() method.
public interface ScanResultConsumer {
public void onDeviceFound(BluetoothDevice device, byte[] scanRecord, int rssi);
public void onScanningStarted();
public void onScanningStopped();
}
Now we need to implement the scanner object that manages the scanning events:
public class BleScanner {
private static final String TAG = BleScanner.class.getSimpleName();
private BluetoothLeScanner leScanner = null;
private BluetoothAdapter bleAdapter = null;
private Handler uiHandler = new Handler(Looper.getMainLooper);
private ScanResultConsumer scanResultConsumer;
private boolean scanning = false;
private final ArrayList<BluetoothDevice> foundDeviceList = new ArrayList<>();
public BleScanner(Context context) {
final BluetoothManager bluetoothManager = (BluetoothManager)
context.getSystemService(Context.BLUETOOTH_SERVICE);
bleAdapter = bluetoothManager.getAdapter();
if(bleAdapter == null) {
Log.d(TAG, "No bluetooth hardware.");
}
else if(!bleAdapter.isEnabled()){
Log.d(TAG, "Blutooth is off.");
}
}
public void scan(ScanResultConsumer scanResultConsumer, long scanTime){
foundDeviceList.clear();
if (scanning){
Log.d(TAG, "Already scanning.");
return;
}
Log.d(TAG, "Scanning...");
if(leScanner == null){
leScanner = bleAdapter.getBluetoothLeScanner();
}
if(scanTimeMs > 0) {
uiHandler.postDelayed(()-> {
if (scanning) {
Log.d(TAG, "Scanning is stopping.");
if(leScanner != null)
leScanner.stopScan(scanCallBack);
else
Log.d(TAG,"Scanner null");
setScanning(false);
}
}, scanTimeMs);
}
this.scanResultConsumer = scanResultConsumer;
leScanner.startScan(scanCallBack);
setScanning(true);
}
private final ScanCallback scanCallBack = new ScanCallback() {
#Override
public void onScanResult(int callbackType, ScanResult result) {
super.onScanResult(callbackType, result);
if (!scanning){
return;
}
if(foundDeviceList.contains(result.getDevice())) {
// This device has already been found
return;
}
// New device found, add it to the list in order to prevent duplications
foundDeviceList.add(result.getDevice());
if(scanResultConsumer != null) {
uiHandler.post(() -> {
scanResultConsumer.onDeviceFound(result.getDevice(),
result.getScanRecord().getBytes(), result.getRssi());
});
}
}
};
public boolean isScanning(){
return scanning;
}
void setScanning(boolean scanning){
this.scanning = scanning;
uiHandler.post(() -> {
if(scanResultConsumer == null) return;
if(!scanning){
scanResultConsumer.onScanningStopped();
// Nullify the consumer in order to prevent UI crashes
scanResultConsumer = null;
} else{
scanResultConsumer.onScanningStarted();
}
});
}
}
Finally we can use this clean implementation in anywhere we need. But do note that a context must be provided in order to create a BleScanner object.
public class MainActivity extends AppCompatActivity {
private BleScanner bleScanner;
private Button buttonScan
// Other codes...
#Override
public void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Other codes...
bleScanner = new BleScanner(getApplicationContext());
// Other codes...
// For example if you want to start scanning on a button press
// Let's say you have a button called buttonScan and initiated it
buttonScan = findViewById(R.id.scan_button);
buttonScan.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
bleScanner.scan(new ScanResultConsumer {
#Override
public void onDeviceFound(BluetoothDevice device, byte[] scanRecord, int rssi) {
// TODO Here you have a newly found device, do something.
}
#Override
q public void onScanningStarted() {
// TODO Scanning has just started, you may want to make some UI changes.
}
#Override
public void onScanningStopped() {
// TODO Scanning has just stopped, you may want to make some UI changes.
}
});
}
});
}
}
Note: I written this code in a plain editor not in Android Studio. So there may be some errors, let me know if any.
First you should check if your app was granted the location permission(s) in the Settings app > Apps <your_app> > permissions. Some permissions (like ACCESS_*_LOCATION and BLUETOOTH_ADMIN) need to be requested at runtime and granted by the user through a popup. Normally you should get a SecurityException or a logcat warning when trying to execute code requiring permissions which your app doesn't have, but it's not uncommon for android to skip over error handling.
Consider using this method to start the scan in order check its result code for potential additional info about what is (not) going on.
You might also get some clues by logging all actions received in BTReceiver.onReceive(), not just action found.
Lastly check if the location settings on your device to ensure that bluetooth scanning is turned on (Settings app > location > wifi and bluetooth scanning )
I am trying to develop an Android service that runs when a button is pressed and stops when a button is pressed. I am trying to make it run even when the screen turns off whether by screen timeout or power button press. Pretty common concept I bet, but I haven't found a post that makes me realize what I am (most likely obviously) doing wrong.
Manifest has permission
<uses-permission android:name="android.permission.WAKE_LOCK" />
Service gets started from fragment with boolean intent extra to specify if it should acquire wake lock
Intent intent = new Intent(mainActivity.getApplicationContext(), NetworkService.class);
intent.putExtra("Wake Lock", wakeLockBox.isEnabled());
mainActivity.startService(intent);
My Service creation acquires the wakelock with Partial tag.
private PowerManager mPowerManager;
private PowerManager.WakeLock wakeLock;
private boolean wakeLockSet;
// service doing its thing code here
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.d("Service", "Started");
wakeLockSet = intent.getBooleanExtra("Wake Lock", false);
// ...
setWakeLock();
// ...
return START_STICKY;
}
private void setWakeLock()
{
mPowerManager = (PowerManager) getSystemService(getApplicationContext().POWER_SERVICE);
wakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
"NetworkService::WakelockTag");
wakeLock.acquire();
}
Based on what I have seen in previous posts and from testing, the only way for the wakelock to be released is when the Service is destroyed.
#Override
public void onDestroy()
{
// ...
if (wakeLockSet) wakeLock.release();
Log.d("Service", "Shutdown");
stopSelf();
}
Whenever my screen turns off, the service onDestroy() method is called and the service releases the lock stops itself. So I am confused about how the wakelock works with services that are supposed to run when the screen is off.
I have tried foreground services:
in the fragment
// notification builder made earlier
Intent intent = new Intent(mainActivity.getApplicationContext(), NetworkService.class);
intent.putExtra("Notification", builder.build());
intent.putExtra("Wake Lock", wakeLockBox.isEnabled());
mainActivity.startForegroundService(intent);
then the service creation
private PowerManager mPowerManager;
private PowerManager.WakeLock wakeLock;
private boolean wakeLockSet;
// service doing its thing code here
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
startForeground(400, intent.getExtras().getParcelable("Notification"));
Log.d("Service", "Started");
wakeLockSet = intent.getBooleanExtra("Wake Lock", false);
// ...
setWakeLock();
// ...
return START_STICKY;
}
private void setWakeLock()
{
mPowerManager = (PowerManager) getSystemService(getApplicationContext().POWER_SERVICE);
wakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
"NetworkService::WakelockTag");
wakeLock.acquire();
}
Same results though. Open to any ideas and willing to share more info if needed.
I'm developing lock screen app. Here Lock screen is displayed on the top of the screen using this command "WindowManager.LayoutParams.TYPE_SYSTEM_ERROR;"
But my problem is I can't See the Incoming call Window when the custom lock screen is displayed. Incoming call window is not overrided over my custom lock screen.
1) Is there any permission required for displaying the incoming call window.?
2) We have to add any other codes for answering the incoming class
This is my Lockscreen receiver class
public class LockScreenReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if(action.equals(Intent.ACTION_SCREEN_OFF) || action.equals(Intent.ACTION_BOOT_COMPLETED))
{
Intent i = new Intent(context, MainActivity.class);
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(i);
}
}
In the normal lock screen apps -> They can attend the incoming calls and after attending that call, lock screen is displayed. How ????
Please help me. Thanks in advance
Add receiver in the manifest and ask for permission
<receiver android:name=".IncomingCall">
<intent-filter>
<action android:name="android.intent.action.PHONE_STATE" />
</intent-filter>
</receiver>
<uses-permission android:name="android.permission.READ_PHONE_STATE"></uses-permission>
Create class IncomingCall
public class IncomingCall extends BroadcastReceiver {
public void onReceive(Context context, Intent intent) {
try {
TelephonyManager telephonyManager = (TelephonyManager) context
.getSystemService(Context.TELEPHONY_SERVICE);
MyPhoneStateListener PhoneListener = new MyPhoneStateListener();
// Register listener for LISTEN_CALL_STATE
telephonyManager.listen(PhoneListener, PhoneStateListener.LISTEN_CALL_STATE);
} catch (Exception e) {
e.printStackTrace();
}
Implement PhoneStateListener in LockScreen and call onCallStateChanged
private class LockScreen extends AppCompatActivity implements PhoneStateListener{
public void onCallStateChanged(int state, String incomingNumber) {
//Disable lockscreen when calls come
}
Is there any way to create a service that runs forever on a background for Android user to check whether their screen on or off, etc?
I'm about to create an analytics, so I need to know when the user turn on or turn off their screen.
Thanks, I will appreciate all the input
You may use Android broadcast receiver to detect screen on and off.
Here is a good example of it
https://thinkandroid.wordpress.com/2010/01/24/handling-screen-off-and-screen-on-intents/
you may also follow this thread
https://stackoverflow.com/a/9478013/2784838
You need to create broadcast receiver and manage screen on or off status.
Declare receiver in manifest:
<receiver android:name=".DeviceWakeUpReceiver" />
public class DeviceWakeUpReceiver extends BroadcastReceiver {
private static final String TAG = "DeviceWakeUpService";
#Override
public void onReceive(Context context, Intent intent) {
Log.d(TAG, "onReceive() called");
if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) {
//End service when user phone screen off
} else if (intent.getAction().equals(Intent.ACTION_SCREEN_ON)) {
//Start service when user phone screen on
}
}
}
You cannot use a BroadcastReceiver for receiving screen off/on events.
Write a intent service which is started via boot complete listener and register for Intent.ACTION_SCREEN_OFF and Intent.ACTION_SCREEN_ON.
IntentFilter filter = new IntentFilter(Intent.ACTION_SCREEN_ON);
IntentFilter filter = new IntentFilter(Intent.ACTION_SCREEN_OFF);
registerReceiver(new ScreenOffOnReceiver(), filter);
class ScreenOffOnReiver extends BroadcastReceiver {
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) {
// Screen OFF
else if (intent.getAction().equals(Intent.ACTION_SCREEN_ON)) {
// Screen ON
}
}
}
I tried to create a audioReceiver Broadcast. To allow my user to ONLY listen to music if the HeadSet in plug-in.
Here is the code :
private BroadcastReceiver audioReceiver = new BroadcastReceiver()
{ #Override
public void onReceive(Context context, Intent intent)
{ AudioManager audio = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
headsetIsPluggedIn = (intent.getExtras().getInt("state")==1);
if(headsetIsPluggedIn) //plugged
{ Log.d("", "BroadcastReceiver - Unmute sound");
audio.setStreamMute(AudioManager.STREAM_MUSIC, false);
}
else //unplugged
{ Log.d("", "BroadcastReceiver - Mute sound");
audio.setStreamMute(AudioManager.STREAM_MUSIC, true);
// Inform user
Toast.makeText(DuplicatedPlayerActivity.this, "Please plug in your headset to enjoy the sound.", Toast.LENGTH_SHORT).show();
}
}
};
#Override
public void onResume() {
super.onResume();
if (HEADSET_ONLY) { registerReceiver(audioReceiver, new IntentFilter(Intent.ACTION_HEADSET_PLUG)); }
Manifest
<receiver android:name="com.juno.brheadset.HeadsetStateReceiver">
<intent-filter>
<action android:name="android.intent.action.HEADSET_PLUG"/>
</intent-filter>
</receiver>
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS"/>
OK, Here is the fun part. If you restart the device, run my app. This function will not work.
If you insert the headset jack in the phone at lest once! quit my app, restart the app. The function will work fine, until the user restart the phone again.
Now, why does this function only works if the user insert the jack in the phone?
"Now, Why does this function only works if the user insert the jack in the phone ?" --> Because you have written your code inside the receiver of action "android.intent.action.HEADSET_PLUG". Your code will only execute when you receive the headset_plug broadcast.