I'd like to somehow stop Bluetooth from changing the volumes when it connects and disconnects. I just want them to stay where they are. How could I go about this? I know how to run services and I can set up listeners, but the following has no effect:
final IntentFilter bluetoothConnectedFilter = new IntentFilter( BluetoothDevice.ACTION_ACL_CONNECTED );
bluetoothConnectedReceiver = new BroadcastReceiver() {
#Override
public void onReceive( Context context, Intent intent ) {
// Change volumes programmatically (code already tested and working elsewhere)
}
};
Thanks for any help.
Related
From the stackoverflow and many blogs, i surely understand that foreground service never run without notification in API>25. But still i confuse that Is notification mandory while app is running on screen or visible.
For eg. no need of notification when user stand within app. So is this possible to remove notification while app running ?
In service class
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
......
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
Notification.Builder builder = new Notification.Builder(this, ANDROID_CHANNEL_ID)
.setContentTitle(getString(R.string.app_name))
.setContentText(text)
.setAutoCancel(true);
Notification notification = builder.build();
startForeground(1, notification);
}
return START_NOT_STICKY;
}
In activity
Intent myService = new Intent(this, MyService.class);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
startForegroundService(myService);
} else {
startService(myService);
}
It's not possible to remove the notification while the foreground service is running, but it is possible to change your foreground service back into a "regular" service. This removes the need for a notification. In fact, the function to use,
stopForeground(boolean removeNotification)
...includes a removeNotification parameter just for that purpose. You service can switch from being "foreground" to "regular" on demand, by alternating calls to startForeground() and stopForeground().
In case it's not clear, you'd probably want to call stopForeground() whenever you have at least one Activity in a "started" state. This is something you'd have to track manually. Then, when the number of "started" activities reaches 0, you'd call startForeground().
EDIT
One approach is to use a bound service. Then, it's easy to call stopForeground() on it when you want.
Assume you have a single Activity. You can bind it to the service (see this doc or use one of these examples). Then your onServiceConnected() function could look like this (adapted from the Google example):
//MyActivity.java:
#Override
public void onServiceConnected(ComponentName className, IBinder service) {
LocalBinder binder = (LocalBinder) service;
mService = binder.getService();
mService.stopForeground(true); //This makes the notification go away
bound = true;
}
...
#Override
protected void onStart() {
super.onStart();
// Bind to the service
bindService(new Intent(this, MyService.class), this, Context.BIND_AUTO_CREATE);
}
#Override
protected void onStop() {
super.onStop();
// Unbind from the service
if (bound) {
Notification.Builder builder = new Notification.Builder(this, ANDROID_CHANNEL_ID)
.setContentTitle(getString(R.string.app_name))
.setContentText(text)
.setAutoCancel(true);
Notification notification = builder.build();
mService.startForeground(1, notification); //This brings the notification back! Service is already running, and continues to run.
unbindService(this);
bound = false;
}
}
No, it is mandatory even your app is running in foreground your foreground service need a notification.
You won't able to hide it.
Why :
You can use any other background task handler like intent service, job sclr but things is designed defferent for foreground service your user understand that event i will close this one of it's progress is going to keep running but things is defferent with background service your know it will do something in background but when system decide it's best time to do it not when your app want (as like in foreground service).
One more case ex :
Suppose your app in foreground battery level is lower than expected by user or system your foreground service will execute instantly no matter what so it's important for your user to know this it's running and take my resources (battery, data, etc)
Hopefully you got my mean 🙂
I have an app that requires the use of Bluetooth to send data like 4-5 numbers and 2-3 texts between devices but i am new to java and the guide from google developers page is a little difficult for me to understand.
In order to make it easier for anyone whiling to help me i will write down in steps what i have done so far.
1. I have asked for permissions in manifest:
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
2. I got the default adapter in my activity:
final BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
3. I created a button that when clicked the device scans for other devices:
bt_scan.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
//first checks if bluettoth is enabled
if (!mBluetoothAdapter.isEnabled()) {
//if not it enables it
Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);
}
// Register for broadcasts when a device is discovered.
IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND);
registerReceiver(mReceiver, filter);
}
});
4. When a device is found, get the device information:
// Create a BroadcastReceiver for ACTION_FOUND.
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
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);
String deviceName = device.getName();
String deviceHardwareAddress = device.getAddress(); // MAC address
}
}
};
5. On destroy unregister the ACTION_FOUND receiver:
#Override
protected void onDestroy() {
super.onDestroy();
// Don't forget to unregister the *ACTION_FOUND* receiver.
unregisterReceiver(mReceiver);
}
6. I have created a second button that when clicked it enables discoverability (which must be clicked first from device A in order for scan button in device B, finds the device A):
bt_enable.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent discoverableIntent = new
Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
discoverableIntent.putExtra( BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION,300);
startActivity(discoverableIntent);
}
});
Questions :
A. In step 3 what REQUEST_ENABLE_BT is for?
B. Is this all i need to establish a connection without any problems between two devices?
C. If i want to connect more than two devices, is there anything else i must add?
Q. What is REQUEST_ENABLE_BT for?
Let me try to comment the code
// If bluetooth is not switched on
if ( ! mBluetoothAdapter.isEnabled() ) {
// Create a system request to enable bluetooth
Intent enableBtIntent = new Intent( BluetoothAdapter.ACTION_REQUEST_ENABLE );
// Queue the request to pops the bluetooth dialogue
startActivityForResult( enableBtIntent, REQUEST_ENABLE_BT );
}
// Standby for device found, Bluetooth may still be disabled at this point
IntentFilter filter = new IntentFilter( BluetoothDevice.ACTION_FOUND );
registerReceiver( mReceiver, filter );
// Now that we are done, bluetooth dialogue will popup
// When it's done Android calls our onActivityResult
// (because we queued it with startActivityForResult).
Q. Is this all I need to establish a connection?
I think there are two more more steps you need to do:
A. Find the device, between step 3 and 4.
Just enabling Bluetooth does not mean it'll automatically scan nearby devices, because scanning cost battery and degrades existing connections.
But with BLUETOOTH_ADMIN permission your app can start and stop the scan.
You can also get previously paired device without scan.
Start Scan: BluetoothAdapter.startDiscovery() This will call ACTION_FOUND for each device found, which fit your code.
List of paired devices: BluetoothAdapter.getBondedDevices() Previously paired Bluetooths can be found in this Set without scanning or BLUETOOTH_ADMIN, and can be connected directly. Whether the device is actually online is unknown until successful or failure, though.
B. Establish the data connection, between 4 and 5.
A device connection is like connecting a network cable.
The computers are physically connected with IP, but your programs still need to open sockets for actual data transfer.
Connection: BluetoothDevice.createRfcommSocketToServiceRecord(uuid) Creates a socket from which data can be go through InputStream and OutputStream.
Don't forget to stop the scan: BluetoothAdapter.cancelDiscovery()
You seems to want to make an M2M messaging app, so I've skipped Bluetooth Low Energy (BLE).
Q. If I want to connect more than two devices, is that all?
As far as "multiple connection" part is concerned, no, you don't need to do anything special to connect to multiple devices at the same time.
The "management" is arguably the hard part, though.
For example you'd normally want to keep a list of the devices, and have a UI that let user selectively disconnect a device, all of which must respond to unexpected disconnections or switching off bluetooth (by user, by another app, or by the system such as low-power mode).
Depends on what you actually want to do with the bluetooth devices, you may need code to remember each one's state too.
Again with error handling.
So, do expect the final code will be a bit more developed.
I would like to answer Question A
A. In step 3 what REQUEST_ENABLE_BT is for?
private static final int REQUEST_ENABLE_BT = 1;
REQUEST_ENABLE_BT is simply an integer value which identifies your request. When you receive the result Intent, the callback onActivityResult(int requestCode, int resultCode, Intent data) provides the same request code to you. In this way you can handle results from other activites
Suppose you have Activity A from where you have requested to enable bluetooth
Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);
When device's bluetooth gets enable, a method onActivityResult(int requestCode, int resultCode, Intent data) will get invoked on Activity A. This method onActivityResult() is a callback method. This method will pass back the request code to the calling activity (Activity A) as soon as bluetooth gets enable. You have to override this method in your Activity A to handle results.
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data)
{
if(requestCode == REQUEST_ENABLE_BT)
Log.d("BLUETOOTH", "Successfully enabled");
}
For the many threads, blogs, examples and tutorials on the topic of Broadcast Receivers and mobile data connectivity i have not seen this question asked or answered.
I believe, based on experimenting with one of my Apps, that the answer to this question is a distinct NO, that while WiFi is enabled, a Broadcast Receiver listening for Mobile Data CONNECTIVITY_CHANGE does not receive a broadcast notification when that event occurs. If i am wrong and have missed something please let me know.
My App is a home screen Widget with two classes, ActiveMobileData is the AppWidgetProvider and ConnectivityChangeReceiver is the BroadcastReceiver. The AppWidgetProvider class is my first App which i put together earlier this year mainly from code widely available in a book, on StackOverflow and on various blogs etc. There is no App just the home screen widget. It simply toggles a home screen icon between red and green to indicate the current mobile data state. It has worked perfectly for several months with about 100 users.
I decided to add the BroadcastReceiver to pick up clicks from Settings. This code is also straight forward - it determines the current state of mobile data, and uses a global boolean variable set by AppWidgetProvider to determine if the home screen icon is red or green. Then it simply ensures that the icon color matches the mobile data state.
It all works except when WiFi is enabled it does not get a notification. If there is a way around this limitation i would appreciate hearing about it.
Following is the code for the widget and then for the receiver. I left out some details to keep it somewhat brief. iconEnabled is the shared global boolean variable ...
public class ActiveMobileData extends AppWidgetProvider {
static boolean iconEnabled;
#Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction() != null)
super.onReceive(context, intent);
else {
context.startService(new Intent(context, ToggleService.class));
}
}
#Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[]appWidgetIds) {
context.startService(new Intent(context, ToggleService.class));
}
public static class ToggleService extends IntentService {
public ToggleService() {
super("ActiveMobileData$ToggleService");
}
#Override
protected void onHandleIntent(Intent intent) {
ComponentName cn = new ComponentName(this, ActiveMobileData.class);
AppWidgetManager mgr = AppWidgetManager.getInstance(this);
mgr.updateAppWidget(cn, buildUpdate(this));
}
private RemoteViews buildUpdate(Context context) {
RemoteViews updateViews = new RemoteViews(context.getPackageName(), R.layout.widget);
if (!isMobileDataEnabled(getApplicationContext())) {
updateViews.setImageViewResource(R.id.mobileDataState, R.mipmap.ic_launcher_g);
enableMobileData(getApplicationContext(), true);
iconEnabled = true;
} else {
updateViews.setImageViewResource(R.id.mobileDataState, R.mipmap.ic_launcher_r);
enableMobileData(getApplicationContext(), false);
iconEnabled = false;
}
Intent i = new Intent(this, ActiveMobileData.class);
PendingIntent pi = PendingIntent.getBroadcast(context, 0, i, 0);
updateViews.setOnClickPendingIntent(R.id.mobileDataState, pi);
return updateViews;
}
public boolean isMobileDataEnabled(Context context) {
// ... the code here is the one that uses Java reflection
}
private void enableMobileData(Context context, boolean enabled) {
// ... the code here is the one that uses Java reflection
}
} // public static class ToggleService
} // public class ActiveMobileData
Following is the code for the BroadcastReceiver ...
public class ConnectivityChangeReceiver extends BroadcastReceiver {
#Override
public void onReceive (Context context, Intent intent) {
handleIntent(context);
}
protected void handleIntent(Context context) {
ComponentName cn = new ComponentName(context, ActiveMobileData.class);
AppWidgetManager mgr = AppWidgetManager.getInstance(context);
mgr.updateAppWidget(cn, buildUpdate(context));
}
private RemoteViews buildUpdate(Context context) {
RemoteViews updateViews = new RemoteViews(context.getPackageName(), R.layout.widget);
if (!ActiveMobileData.iconEnabled && isMobileDataEnabled(context)) {
ActiveMobileData.iconEnabled = true;
updateViews.setImageViewResource(R.id.mobileDataState, R.mipmap.ic_launcher_g);
Intent i = new Intent(context, ActiveMobileData.class);
PendingIntent pi = PendingIntent.getBroadcast(context, 0, i, 0);
updateViews.setOnClickPendingIntent(R.id.mobileDataState, pi);
} else
if (ActiveMobileData.iconEnabled && !isMobileDataEnabled(context)) {
ActiveMobileData.iconEnabled = false;
updateViews.setImageViewResource(R.id.mobileDataState, R.mipmap.ic_launcher_r);
Intent i = new Intent(context, ActiveMobileData.class);
PendingIntent pi = PendingIntent.getBroadcast(context, 0, i, 0);
updateViews.setOnClickPendingIntent(R.id.mobileDataState, pi);
}
return updateViews;
}
private boolean isMobileDataEnabled(Context context) {
// ... Identical code to that in the AppWidgetProvider
}
} // class ConnectivityChangeReceiver
I don't know offhand, but I can point you to the 2 best places to look.
Best bet would be to look in detail into the JavaDoc for ConnectivityManager.html#CONNECTIVITY_ACTION and then the source code for the ConnectivityManager that is online on GrepCode
In particular comments within the source code often have very informative information that doesn't exist elsewhere.
Update:
After reading the javadoc for CONNECTIVITY_ACTION again, I believe that you are correct because it say A change in network connectivity has occurred. A default connection has either been established or lost. NOTE: Default Conn. NOT 'A Conn.' So it only gets launched when the 'default' changes. So if you lose 3g/4g/etc while on WIFI then I don't think this gets launched.
However there 'is' something you 'can' do... (but only when your widget is running) (I'm actually not 100% sure a 'widget' CAN do this... b/c I generally work with teaching services/AIDL/ContentProviders/etc (aka. 'backend' stuff within the platform) But you can put a 'refresh' button on your widget that can query to GET ALL NETWORKS and then parse through all that data and display which networks 'are' active, etc.
Also there is the option. You could make pending intents for your broadcast receiver(s) (I'd recommend just 1 BR and have different payloads so you can sort them for what is being notified) then register each of those pending intents as a call back with the ConnectivityManager to notify it whenever a 'network' that 'matches' the NetworkRequest exists. This will notify you at least when they 'come alive'...
(this next idea would likely require you to make a service with a separate thread to prevent ANR)
now when they 'die'... you 'could' setup a TCP connection and see when it dies... (not 'good' but might be only 'viable' option) (and if you are are 'generous' with trying to not wake up the phone, the battery impact could be minimal)
I'm trying to simply set a proximity later for an area an for testing, I simply added this to the onCreate method of my main activity.
public void onCreate(Bundle bndBundle) {
IntentFilter filter = new IntentFilter(WidgetService.ACTION_STOP_PROXIMITY);
registerReceiver(new ProximityIntentReceiver(), filter);
LocationManager locManager = (LocationManager) this.getSystemService(LOCATION_SERVICE);
Intent ittIntent = new Intent(this, ProximityIntentReceiver.class);
ittIntent.putExtra(WidgetService.KEY_STOP_IDENTIFIER, 1000);
PendingIntent pitIntent = PendingIntent.getBroadcast(this, 0, ittIntent, 0);
locManager.addProximityAlert(60.15769, 24.94150, 150, -1, pitIntent);
super.onCreate(bndBundle);
getActionBar().setDisplayHomeAsUpEnabled(false);
}
..and here's the simple receiver class that I'm using
public class ProximityIntentReceiver extends BroadcastReceiver {
private static final int NOTIFICATION_ID = 1000;
#Override
public void onReceive(Context context, Intent intent) {
String key = LocationManager.KEY_PROXIMITY_ENTERING;
Boolean entering = intent.getBooleanExtra(key, false);
if (entering) {
Log.d(getClass().getSimpleName(), "entering");
}
else {
Log.d(getClass().getSimpleName(), "exiting");
}
}
}
I'm testing this on my emulator and when I use the DDMS console to set the co-ordinates of the phone manually, I still don't see the log message.
My manifest file doesn't have any special code. I've added the correct permissions and have the code for a simple activity- no services or anything.
I read through a whole bunch of posts on StacKOverflow but I haven't been able to resolve the issue. Am I missing something in my snippet?
You are registering this receiver dynamically, through registerReceiver(), to have it respond to broadcasts whose action string is WidgetService.ACTION_STOP_PROXIMITY.
However, the actual broadcast you are sending is trying to use an explicit Intent, identifying your receiver class. This does not line up with the IntentFilter that you are using with registerReceiver().
Either:
Register your receiver in the manifest and get rid of registerReceiver(), in which case your explicit Intent will work, or
Use new Intent(WidgetService.ACTION_STOP_PROXIMITY) instead of new Intent(this, ProximityIntentReceiver.class), so your Intent lines up with your IntentFilter
You cannot use explicit Intent objects to send broadcasts to receivers registered via registerReceiver(). An explicit Intent will only work with a manifest-registered receiver.
make sure you type in the right coordinates. in DDMS they're reversed, longitude first, then latitude
I am writing a program which respond when a new process got start.
private final BroadcastReceiver mBatInfoReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context arg0, Intent intent) {
// what to write here
}
};
I do not know that what to write instead of comments to get processes info.
thanks.
You can't monitor process starts using a BroadcastReceiver. You should look at this: you would have to run it in a loop, but that's probably your best bet.