I am working on an android app with an email feature. I want my users to be able to compose and send emails while in airplane mode. For that I need some sort of queue that can check if there is network and send, etc. I image this must have been done 100s of times. But I am not really sure why my searches aren't turning up much. Does anyone know of a library or git project that I can use to accomplish this? If not, does anyone know how to accomplish this?
I believe it is called the Queue and send pattern.
Update
I am starting a bounty on this question. What I hope for is a working example that does not use SMS. For my particular case I am working on an Appengine Connected Android Project. The client needs to send data (String, Bitmap, etc under a particular POJO say Dog) to the server. I want to be able to queue up these data somehow. I can use Gson to save data to file, etc. The bottom line is that I need to be able to check for network. When there is network I dequeue my queue into the server. If there is no network, I keep saving into the queue.
My queue can be Queue<Dog>, where Dog is my class with fields such as Bitmap (or path to image), String, long, etc.
I am looking for a working example. It can be very simple, but the example must work. A git zip would be great. I am giving up close to half of my points for this question.
class Dog{
String dogname;
String pathToImage;
int dogAge;
//etc.
}
//Design pattern for sending Dog to server
0) Unmarshall queue from file using Gson
1) Add dog to queue
2) If there is network, loop through queue and send data to server
3) if there is no network save queue to file
//Ideally, as soon as there is network, the method should be able to detect so and run to send data to server
First you need to set up a receiver to watch the wifi connection to see when they have data, you could also check for normal 3g/4g connections and make a broadcast receiver for that as well. todo this let use implement a broadcast receiver for connection status changes. put something like this in the manifest in the application tag
<receiver android:name=".NetworkChangeReceiver" >
<intent-filter>
<action android:name="android.net.conn.CONNECTIVITY_CHANGE" />
</intent-filter>
</receiver>
now we need to make the receiver we just defined in the manifest
public class NetworkChangeReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
//here, check that the network connection is available. If yes, start your email service. If not, stop your email service.
ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo info = cm.getActiveNetworkInfo();
if (info != null) {
if (info.isConnected()) {
//start service
Intent intent = new Intent(this, ItemServiceManager.class);
startService(intent);
}
else {
//stop service
Intent intent = new Intent(this, ItemServiceManager.class);
stopService(intent);
}
}
}
}
What this does is puts a big fat antenna called NetworkChangeReceiver out in android land, that is fine tuned to listen in on when android has something to say about a change in the data connection status.
now you need to build your ItemServiceManager.class which should read from a database (it should also extend Service. It should choose the oldest item in the database, (email it, text it, upload to server, whatever), and if the connection was successful then remove the item from the database, and load the next oldest one. If there is no more then close the service and the broadcast receiver.
If you have a connection and the user needs to send more data, then add it to the database, and then make sure the service is started. Maybe notify it that it should double check the database (after a few seconds) before deciding it can close because nothing is there.
This is how you might disable your broadcast receiver.
PackageManager packageManager = context.getPackageManager();
ComponentName componentName = new ComponentName(context, NetworkChangeReceiver.class);
packageManager.setComponentEnabledSetting(componentName,PackageManager.COMPONENT_ENABLED_STATE_DISABLED, PackageManager.DONT_KILL_APP);
When a new item is to be uploaded, if there is no web connection, the email should be saved to the database and the broadcast receiver should be started to know when internet is back so it can know when to upload. You might start it up like this.
PackageManager packageManager = context.getPackageManager();
ComponentName componentName = new ComponentName(context, NetworkChangeReceiver.class);
packageManager.setComponentEnabledSetting(componentName,PackageManager.COMPONENT_ENABLED_STATE_ENABLED,PackageManager.DONT_KILL_APP);
The whole point is you only care about connection broadcasts when you have something stored to be uploaded but can not upload it because of no data connection. When you have nothing to upload, don't waste processing and battery by keeping your receiver/service around. And when you do have emails waiting, then start up you broadcastreceiver, to know when you have data connection so that you can start uploading.
I do not think anyone is going to write a whole working solution for you, hopefully this is more than enough to get you on your way.
Edit:
Another thing you can do, is let the server allow acceptance of an array of your items, that way you can just upload it all at once when you get a valid connection. Generally you would do this if each item was decently small. But if you are uploading pictures or videos or anything large, best to do it one at a time probably.
Related
I'm using Eclipse's Paho android library. This library internally starts a Service to fetch data. Now when my app is in background and push notification comes, Paho's service works well for pre-oreo devices. But on Oreo device, this work for few minutes duration after app goes to the background state. After this duration, although I'm sending high priority GCM message, service won't starts and gives warning in logcat Background start not allowed. As stated in offical docs, for high priority GCM messages, app becomes whitelisted for few minutes. In this case, it should work for high priority GCM message.
From my understanding app should become whitelisted whenever high priority GCM arrives. Is it correct?
To be ready for Android O:
1) Instead of IntentService; your service needs to extend JobIntentService.
2) Instead of onHandleIntent; you need to use onHandleWork.
3) Instead of startService; you need to use enqueueWork.
Check this out.
https://developer.android.com/reference/android/support/v4/app/JobIntentService.html
When dealing with broadcasts, you need to make sure the intent is explicit.
private static void sendImplicitBroadcast(Context ctxt, Intent i) {
PackageManager pm=ctxt.getPackageManager();
List<ResolveInfo> matches=pm.queryBroadcastReceivers(i, 0);
for (ResolveInfo resolveInfo : matches) {
Intent explicit=new Intent(i);
ComponentName cn=
new ComponentName(resolveInfo.activityInfo.applicationInfo.packageName,
resolveInfo.activityInfo.name);
explicit.setComponent(cn);
ctxt.sendBroadcast(explicit);
}
}
This was from https://commonsware.com/blog/2017/04/11/android-o-implicit-broadcast-ban.html
Hi i am running a background service using alaram manager its working fine but for some mi devices background service is not working.I used sevices but it is not working how to run my background service in mi ?
MI UI has its own security options, so what you need to is not just above mentioned sticky Service,
you need to
Enable Autostart
go to power setting make changes as per these youtube videos
https://www.youtube.com/watch?v=-Ffgir-QgsU, or refer for this for more suggestions
https://www.quora.com/How-do-I-keep-an-app-running-in-the-background-in-MIUI
then you have created a custom broadcast receiver which will start the service when your service is destroyed
as per this example https://fabcirablog.weebly.com/blog/creating-a-never-ending-background-service-in-android
If the 3rd option doesn't work onDestroy recall of the service call the custom broadcast receiver on
w
public void onTaskRemoved(Intent rootIntent) {
super.onTaskRemoved(rootIntent);
Log.e(TAG, " In recieve Custome Broadcast receiver");
Intent broadcastIntent = new Intent("ac.in.ActivityRecognition.RestartSensor");
sendBroadcast(broadcastIntent);
}
Intent intent = new Intent(Intent.ACTION_MAIN);
intent.setComponent(new ComponentName("com.android.settings","com.android.settings.Settings$HighPowerApplicationsActivity"));
startActivity(intent);
try this code
it will open one setting page
then find your app and then tap "Don't Optimize"
it will turn off battery optimization and your background services run without problem
When you start a service by extending an Service class than you will get the call inside OnStartCommand() this method has three types of return type on the basis of this return type operating system itself manage when to start a service.
So suppose if your service gets killed in between due to low memory or any other issue when you return a correct type from onStartCommand() than os will take care of when to start service again.
Three return types are:
START_STICKY : When this is the return type than os takes the guarantee to restart the service again if its get killed it will definitely start you service again even if there is no pending intent it will start the service by passing intent as null.
START_NOT_STICKY: says that, after returning from onStartCreated(), if the process is killed with no remaining start commands to deliver, then the service will be stopped instead of restarted. This makes a lot more sense for services that are intended to only run while executing commands sent to them. For example, a service may be started every 15 minutes from an alarm to poll some network state. If it gets killed while doing that work, it would be best to just let it be stopped and get started the next time the alarm fires.
START_REDELIVER_INTENT is like START_NOT_STICKY, except if the service's process is killed before it calls stopSelf() for a given intent, that intent will be re-delivered to it until it completes (unless after some number of more tries it still can't complete, at which point the system gives up). This is useful for services that are receiving commands of work to do, and want to make sure they do eventually complete the work for each command sent.
Update: To state this first: I'm looking for a programmatical way. I know it is easily possible with emulators, but I'm looking for a way to have it implemented in an actual application on my phone.
I've been playing around with this for a while now, although I can write messages to the inbox or outbox with
ContentValues values = new ContentValues();
values.put("address", "5551");
values.put("body", "the text of this message");
getContentResolver().insert(Uri.parse("content://sms/inbox"),values)
and of course
<uses-permission android:name="android.permission.WRITE_SMS"/>
<uses-permission android:name="android.permission.SEND_SMS"/>
<uses-permission android:name="android.permission.READ_SMS"/>
The WRITE_SMSis there just for some of the following, because with all the things I tried I could not get the system to receive a notification. I thought about investigating the code of the built-in SMS app but could not find it.
Here come the things I tried:
context.getContentResolver().notifyChange(Uri.parse("content://sms/inbox",null);
has just the same non-effect like:
Intent intent = new Intent("android.provider.Telephony.SMS_RECEIVED");
byte[] b = (byte[])(SmsMessage.getSubmitPdu("5551","5552","some_text",false).encodedMessage);
Object[] vrs = {b};
intent.putExtra("pdus",vrs);
sendBroadcast(intent);
As a workaround right now I'm calling the sms-list:
Intent intent = new Intent("android.intent.action.MAIN");
intent.setComponent(new ComponentName("com.android.mms","com.android.mms.ui.ConversationList"));
startActivity(intent);
Any ideas or hints?
Ok, so I have been browsing the android code, especially
http://www.java2s.com/Open-Source/Android/android-platform-apps/Mms/com/android/mms/transaction/MessagingNotification.java.htm
To my understanding all I'd need to do is call the public static MessagingNotification.blockingUpdateAllNotifications(context) after writing the SMS. Is there any way I can access this method?
Use the "emulator control" section in DDMS to send test sms/text to your emulator. You can also enter the fake number from which the sms is to be sent.
More information can be found under in the "Spoofing calls or SMS text messages" section of the Using DDMS document in the dev guide
I am developing an application where i have file uri as well as bt device address with me. I need to send the file to the defined bt device. But, the device picker screen should not be shown. It should directly start the device sending.
Obviously, intent:ACTION_SEND is not an option here, as it will show the chooser dialog. The main intension of the application is to bypass the chooser dialog and enable user to send selected file to selected device directly.
So, i was trying the following solution suggested in stack-overflow:
/*BluetoothDevice device;
String filePath = Environment.getExternalStorageDirectory().toString() + "/file.jpg";
ContentValues values = new ContentValues();
values.put(BluetoothShare.URI, Uri.fromFile(new File(filePath)).toString());
values.put(BluetoothShare.DESTINATION, device.getAddress());
values.put(BluetoothShare.DIRECTION, BluetoothShare.DIRECTION_OUTBOUND);
Long ts = System.currentTimeMillis();
values.put(BluetoothShare.TIMESTAMP, ts);
Uri contentUri = getContentResolver().insert(BluetoothShare.CONTENT_URI, values);*/
But unfortunately, it is not working. After getContentResolver().insert, there is no action taken. Needless to say, i have tried various permissions and other stuffs, but to no effect.
So, people who have used this code, please provide your suggestions. Any help to meet the requirement will be very much appreciated.
Does it produce any exception? Please share your Logcat output.
By the way, make use you have the following permission in AndroidManifest.xml
<uses-permission android:name="android.permission.BLUETOOTH"/>
If you are doing a device discovery, add this too in the manifest file
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
I also found this problem. I can show some evidence to solve this problem. After trying this code check outbound transfer queue of your device (to open it, Send a file manually to a device and click the notification icon). Then you can see device has tried to send objects and those were failed. Click on one failure message and you can see pop-up with no file path. I think the problem is though here we are setting the file path using URI to the contentValues it will not be checked in the process. We have to do some thing for this.
I am having a problem where my service is being killed even though I am holding a wake lock and I have called startForeground. When this occurs the tablet (ASUS Transformer TF101), stops the service without calling onDestroy. There are no other apps visible, and log cat shows nothing out of the ordinary (no 'out of memory' message etc). Immediately after being killed, the service restarts.
The app I am developing is a chat client and needs a constant connection, it is also plugin based, so my app is developed as such: Client - HostService - Multiple child 'Services'.
The host service is sticky holds the wake lock and calls startForeground (and displays a notification as such), the child services are not sticky, do not hold wake locks and are background services.
If the client itself is open the issue does not occur, but the model I am going for is that the user can use the device and stay connected (receiving messages etc) without having the client itself open at all times.
Can anybody offer any explanation as to why the service is being killed in this way, and if so prevent it from happening? As the chat clients show when a user logs on and off, and the service dying kills all open connections, this makes the chat client 'bounce'. At present it seems to happen somewhere between every 15 and 45 minutes.
Also, if anybody is aware of a way to keep a socket connection open continuously without holding a wake lock for the entire connection duration, I would love to hear it!
The trimmed test case version of the host service source is below.
public class HostService extends Service
{
PowerManager m_powerManager = null;
PowerManager.WakeLock m_wakeLock = null;
#Override
public IBinder onBind( Intent intent )
{
return m_serviceImplementation;
}
#Override
public void onCreate()
{
super.onCreate();
}
#Override
public void onDestroy()
{
if( m_wakeLock != null )
{
m_wakeLock.release();
m_wakeLock = null;
}
stopForeground( true );
super.onDestroy();
}
#Override
public int onStartCommand( Intent intent, int flags, int startId )
{
// Display a notification about us starting. We put an icon in the
// status bar.
Notification notification = createNotification();
startForeground( R.string.service_running, notification );
if( m_powerManager == null )
{
m_powerManager = (PowerManager)getSystemService(Context.POWER_SERVICE);
}
if( m_wakeLock == null )
{
m_wakeLock = m_powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "Keep background services running");
m_wakeLock.acquire();
}
// We want this service to continue running until it is explicitly
// stopped, so return sticky.
return START_STICKY;
}
/**
* Create a notification to show the service is running
*/
private Notification createNotification()
{
CharSequence text = getText( R.string.service_running );
CharSequence title = getText( R.string.app_name );
// The PendingIntent to launch our activity if the user selects this
// notification
PendingIntent contentIntent = PendingIntent.getActivity( this, 0, new Intent(this, MainChat.class) , 0 );
Notification notification = new Notification( android.R.drawable.sym_action_chat, title, System.currentTimeMillis() );
notification.setLatestEventInfo( this, title, text, contentIntent );
return notification;
}
private final IMessageInterface.Stub m_serviceImplementation = new IMessageInterface.Stub()
{
...
};
}
Android Manifest (relevant bits):
<uses-sdk android:minSdkVersion="11" android:targetSdkVersion="11" />
<service android:name="com.mydomain.chatClient.server.HostService" android:exported="true" android:enabled="true" android:process=":remote"/>
<uses-permission android:name="android.permission.WAKE_LOCK" />
I am having a problem where my service is being killed even though I am holding a wake lock and I have called startForeground.
startForeground() reduces the likelihood of a service being killed, but it does not prevent it.
The app I am developing is a chat client and needs a constant connection, it is also plugin based, so my app is developed as such: Client - HostService - Multiple child 'Services'.
I recommend getting rid of one of those layers. Even if the OS doesn't shut you down, many users will (e.g., task killer, Running Services in Settings), considering you to be running too many services.
If the client itself is open the issue does not occur, but the model I am going for is that the user can use the device and stay connected (receiving messages etc) without having the client itself open at all times.
I recommend making that optional. You may think it's sexy. Some of your users will attack you for wasting their battery.
Can anybody offer any explanation as to why the service is being killed in this way, and if so prevent it from happening?
I'd start by getting rid of android:process=":remote". You don't need it. You don't want it. You may be hurting yourself by having it, as it may accelerate Android's interest in getting rid of your service. You absolutely are hurting users by having it, because you are wasting RAM for no good reason.
Then, I'd get rid of the plugins, if you implemented those as separate applications. In that case, each one of those will be running in its own process, wasting yet more RAM. Besides, your current implementation would be flawed, as you would be stuck having your service be named com.mydomain.chatClient.server.HostService until the end of time, since you didn't use an <intent-filter> to separate the concerns of "what the service is named internally" and "what the service is called by other separately-installed applications that wish to use it". And if you didn't implement the plugins as separate applications, then I fail to see the value in having them be in separate services, rather than folding them all into the one service.
Also, if anybody is aware of a way to keep a socket connection open continuously without holding a wake lock for the entire connection duration, I would love to hear it!
If the socket is on wireless data, instead of WiFi, you do not need a WakeLock all the time. The socket will remain open, and incoming packets on that socket will wake up your code. At that point, you'd want to grab a WakeLock long enough for you to do whatever you're doing with the data when it arrives, then release the WakeLock.
If you are on WiFi, though, this trick doesn't work, so a WakeLock (and probably a WifiLock) will be required.