mirror of
https://github.com/cwinfo/envayasms.git
synced 2024-11-09 10:20:25 +00:00
add foreground service to keep App in memory (otherwise rate-limiting won't work) and provide notification
This commit is contained in:
parent
a793a5f2e3
commit
9a574b3ab4
@ -84,5 +84,8 @@
|
|||||||
<service android:name=".CheckMmsInboxService">
|
<service android:name=".CheckMmsInboxService">
|
||||||
</service>
|
</service>
|
||||||
|
|
||||||
|
<service android:name=".ForegroundService">
|
||||||
|
</service>
|
||||||
|
|
||||||
</application>
|
</application>
|
||||||
</manifest>
|
</manifest>
|
5
LICENSE
5
LICENSE
@ -38,6 +38,7 @@ org.envaya.kalsms.ui.InertCheckBox and org.envaya.kalsms.ui.CheckableRelativeLay
|
|||||||
is (c) Cédric Caron, released presumably into the public domain at
|
is (c) Cédric Caron, released presumably into the public domain at
|
||||||
http://www.marvinlabs.com/2010/10/custom-listview-ability-check-items/
|
http://www.marvinlabs.com/2010/10/custom-listview-ability-check-items/
|
||||||
|
|
||||||
org.envaya.kalsms.App.chooseOutgoingSmsPackage includes code from Android,
|
org.envaya.kalsms.App.chooseOutgoingSmsPackage and
|
||||||
Copyright 2005-2008 The Android Open Source Project
|
org.envaya.kalsms.ForegroundService include code from Android,
|
||||||
|
Copyright 2005-2009 The Android Open Source Project
|
||||||
See NOTICE
|
See NOTICE
|
@ -7,6 +7,7 @@
|
|||||||
<string name="help">Help</string>
|
<string name="help">Help</string>
|
||||||
<string name="retry_now">Retry</string>
|
<string name="retry_now">Retry</string>
|
||||||
<string name="forward_inbox">Fwd Inbox...</string>
|
<string name="forward_inbox">Fwd Inbox...</string>
|
||||||
|
<string name='service_started'>New SMS will be forwarded to server</string>
|
||||||
<string name='test_senders'>When running KalSMS in Test Mode,
|
<string name='test_senders'>When running KalSMS in Test Mode,
|
||||||
KalSMS will only forward SMS messages from the phone numbers
|
KalSMS will only forward SMS messages from the phone numbers
|
||||||
listed below. (Incoming SMS messages from other phone numbers will be saved
|
listed below. (Incoming SMS messages from other phone numbers will be saved
|
||||||
|
@ -16,10 +16,16 @@ class KalSMS
|
|||||||
const STATUS_FAILED = 'failed';
|
const STATUS_FAILED = 'failed';
|
||||||
const STATUS_SENT = 'sent';
|
const STATUS_SENT = 'sent';
|
||||||
|
|
||||||
|
const MESSAGE_TYPE_SMS = 'sms';
|
||||||
|
const MESSAGE_TYPE_MMS = 'mms';
|
||||||
|
|
||||||
static function new_from_request()
|
static function new_from_request()
|
||||||
{
|
{
|
||||||
$version = @$_POST['version'];
|
$version = @$_POST['version'];
|
||||||
|
|
||||||
|
// If API version changes, could return different KalSMS instance
|
||||||
|
// to support multiple phone versions
|
||||||
|
|
||||||
return new KalSMS();
|
return new KalSMS();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -96,9 +102,9 @@ class KalSMS
|
|||||||
|
|
||||||
class KalSMS_OutgoingMessage
|
class KalSMS_OutgoingMessage
|
||||||
{
|
{
|
||||||
public $id = '';
|
public $id = ''; // ID generated by server
|
||||||
public $to;
|
public $to; // destination phone number
|
||||||
public $message;
|
public $message; // content of SMS message
|
||||||
}
|
}
|
||||||
|
|
||||||
class KalSMS_Action
|
class KalSMS_Action
|
||||||
@ -121,10 +127,37 @@ class KalSMS_Action_Test extends KalSMS_Action
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class KalSMS_MMS_Part
|
||||||
|
{
|
||||||
|
public $form_name; // name of form field with MMS part content
|
||||||
|
public $cid; // MMS Content-ID
|
||||||
|
public $type; // Content type
|
||||||
|
public $filename; // Original filename of MMS part on sender phone
|
||||||
|
public $tmp_name; // Temporary file where MMS part content is stored
|
||||||
|
public $size; // Content length
|
||||||
|
public $error; // see http://www.php.net/manual/en/features.file-upload.errors.php
|
||||||
|
|
||||||
|
function __construct($args)
|
||||||
|
{
|
||||||
|
$this->form_name = $args['name'];
|
||||||
|
$this->cid = $args['cid'];
|
||||||
|
$this->type = $args['type'];
|
||||||
|
$this->filename = $args['filename'];
|
||||||
|
|
||||||
|
$file = $_FILES[$this->form_name];
|
||||||
|
|
||||||
|
$this->tmp_name = $file['tmp_name'];
|
||||||
|
$this->size = $file['size'];
|
||||||
|
$this->error = $file['error'];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
class KalSMS_Action_Incoming extends KalSMS_Action
|
class KalSMS_Action_Incoming extends KalSMS_Action
|
||||||
{
|
{
|
||||||
public $from;
|
public $from; // Sender phone number
|
||||||
public $message;
|
public $message; // The message body of the SMS, or the content of the text/plain part of the MMS.
|
||||||
|
public $message_type; // KalSMS::MESSAGE_TYPE_MMS or KalSMS::MESSAGE_TYPE_SMS
|
||||||
|
public $mms_parts; // array of KalSMS_MMS_Part instances
|
||||||
|
|
||||||
function __construct($kalsms)
|
function __construct($kalsms)
|
||||||
{
|
{
|
||||||
@ -132,6 +165,16 @@ class KalSMS_Action_Incoming extends KalSMS_Action
|
|||||||
$this->type = KalSMS::ACTION_INCOMING;
|
$this->type = KalSMS::ACTION_INCOMING;
|
||||||
$this->from = $_POST['from'];
|
$this->from = $_POST['from'];
|
||||||
$this->message = $_POST['message'];
|
$this->message = $_POST['message'];
|
||||||
|
$this->message_type = $_POST['message_type'];
|
||||||
|
|
||||||
|
if ($this->message_type == KalSMS::MESSAGE_TYPE_MMS)
|
||||||
|
{
|
||||||
|
$this->mms_parts = array();
|
||||||
|
foreach (json_decode($_POST['mms_parts'], true) as $mms_part)
|
||||||
|
{
|
||||||
|
$this->mms_parts[] = new KalSMS_MMS_Part($mms_part);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function get_response_xml($messages)
|
function get_response_xml($messages)
|
||||||
@ -173,8 +216,8 @@ class KalSMS_Action_Outgoing extends KalSMS_Action
|
|||||||
|
|
||||||
class KalSMS_Action_SendStatus extends KalSMS_Action
|
class KalSMS_Action_SendStatus extends KalSMS_Action
|
||||||
{
|
{
|
||||||
public $status;
|
public $status; // KalSMS::STATUS_* values
|
||||||
public $id;
|
public $id; // server ID previously used in KalSMS_OutgoingMessage
|
||||||
|
|
||||||
function __construct($type)
|
function __construct($type)
|
||||||
{
|
{
|
||||||
|
@ -59,6 +59,9 @@ public final class App extends Application {
|
|||||||
// intent to signal to Main activity (if open) that log has changed
|
// intent to signal to Main activity (if open) that log has changed
|
||||||
public static final String LOG_INTENT = "org.envaya.kalsms.LOG";
|
public static final String LOG_INTENT = "org.envaya.kalsms.LOG";
|
||||||
|
|
||||||
|
public static final String START_INTENT = "org.envaya.kalsms.START";
|
||||||
|
public static final String STOP_INTENT = "org.envaya.kalsms.STOP";
|
||||||
|
|
||||||
public static final String QUERY_EXPANSION_PACKS_INTENT = "org.envaya.kalsms.QUERY_EXPANSION_PACKS";
|
public static final String QUERY_EXPANSION_PACKS_INTENT = "org.envaya.kalsms.QUERY_EXPANSION_PACKS";
|
||||||
public static final String QUERY_EXPANSION_PACKS_EXTRA_PACKAGES = "packages";
|
public static final String QUERY_EXPANSION_PACKS_EXTRA_PACKAGES = "packages";
|
||||||
|
|
||||||
@ -142,6 +145,12 @@ public final class App extends Application {
|
|||||||
mmsObserver.register();
|
mmsObserver.register();
|
||||||
|
|
||||||
setOutgoingMessageAlarm();
|
setOutgoingMessageAlarm();
|
||||||
|
updateEnabledNotification();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void updateEnabledNotification()
|
||||||
|
{
|
||||||
|
startService(new Intent(this, ForegroundService.class));
|
||||||
}
|
}
|
||||||
|
|
||||||
public synchronized String chooseOutgoingSmsPackage()
|
public synchronized String chooseOutgoingSmsPackage()
|
||||||
|
@ -42,8 +42,15 @@ public class CheckMmsInboxService extends IntentService
|
|||||||
// times if we don't delete them.
|
// times if we don't delete them.
|
||||||
mmsUtils.markOldMms(mms);
|
mmsUtils.markOldMms(mms);
|
||||||
|
|
||||||
|
if (mms.isForwardable())
|
||||||
|
{
|
||||||
app.forwardToServer(mms);
|
app.forwardToServer(mms);
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
app.log("Ignoring incoming MMS from " + mms.getFrom());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
188
src/org/envaya/kalsms/ForegroundService.java
Executable file
188
src/org/envaya/kalsms/ForegroundService.java
Executable file
@ -0,0 +1,188 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2009 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.envaya.kalsms;
|
||||||
|
|
||||||
|
import android.app.Notification;
|
||||||
|
import android.app.NotificationManager;
|
||||||
|
import android.app.PendingIntent;
|
||||||
|
import android.app.Service;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.os.IBinder;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
import java.lang.reflect.InvocationTargetException;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
import org.envaya.kalsms.ui.Main;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Service running in foreground to make sure App instance stays
|
||||||
|
* in memory (otherwise we could lose timestamps of sent messages
|
||||||
|
* which could cause us to exceed Android's SMS sending limit)
|
||||||
|
*
|
||||||
|
* Also adds notification to status bar.
|
||||||
|
*/
|
||||||
|
public class ForegroundService extends Service {
|
||||||
|
|
||||||
|
private App app;
|
||||||
|
|
||||||
|
private static final Class<?>[] mSetForegroundSignature = new Class[] {
|
||||||
|
boolean.class};
|
||||||
|
private static final Class<?>[] mStartForegroundSignature = new Class[] {
|
||||||
|
int.class, Notification.class};
|
||||||
|
private static final Class<?>[] mStopForegroundSignature = new Class[] {
|
||||||
|
boolean.class};
|
||||||
|
|
||||||
|
private NotificationManager mNM;
|
||||||
|
private Method mSetForeground;
|
||||||
|
private Method mStartForeground;
|
||||||
|
private Method mStopForeground;
|
||||||
|
private Object[] mSetForegroundArgs = new Object[1];
|
||||||
|
private Object[] mStartForegroundArgs = new Object[2];
|
||||||
|
private Object[] mStopForegroundArgs = new Object[1];
|
||||||
|
|
||||||
|
void invokeMethod(Method method, Object[] args) {
|
||||||
|
try {
|
||||||
|
mStartForeground.invoke(this, mStartForegroundArgs);
|
||||||
|
} catch (InvocationTargetException e) {
|
||||||
|
// Should not happen.
|
||||||
|
Log.w("ApiDemos", "Unable to invoke method", e);
|
||||||
|
} catch (IllegalAccessException e) {
|
||||||
|
// Should not happen.
|
||||||
|
Log.w("ApiDemos", "Unable to invoke method", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is a wrapper around the new startForeground method, using the older
|
||||||
|
* APIs if it is not available.
|
||||||
|
*/
|
||||||
|
void startForegroundCompat(int id, Notification notification) {
|
||||||
|
// If we have the new startForeground API, then use it.
|
||||||
|
if (mStartForeground != null) {
|
||||||
|
mStartForegroundArgs[0] = Integer.valueOf(id);
|
||||||
|
mStartForegroundArgs[1] = notification;
|
||||||
|
invokeMethod(mStartForeground, mStartForegroundArgs);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fall back on the old API.
|
||||||
|
mSetForegroundArgs[0] = Boolean.TRUE;
|
||||||
|
invokeMethod(mSetForeground, mSetForegroundArgs);
|
||||||
|
mNM.notify(id, notification);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is a wrapper around the new stopForeground method, using the older
|
||||||
|
* APIs if it is not available.
|
||||||
|
*/
|
||||||
|
void stopForegroundCompat(int id) {
|
||||||
|
// If we have the new stopForeground API, then use it.
|
||||||
|
if (mStopForeground != null) {
|
||||||
|
mStopForegroundArgs[0] = Boolean.TRUE;
|
||||||
|
try {
|
||||||
|
mStopForeground.invoke(this, mStopForegroundArgs);
|
||||||
|
} catch (InvocationTargetException e) {
|
||||||
|
// Should not happen.
|
||||||
|
Log.w("ApiDemos", "Unable to invoke stopForeground", e);
|
||||||
|
} catch (IllegalAccessException e) {
|
||||||
|
// Should not happen.
|
||||||
|
Log.w("ApiDemos", "Unable to invoke stopForeground", e);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fall back on the old API. Note to cancel BEFORE changing the
|
||||||
|
// foreground state, since we could be killed at that point.
|
||||||
|
mNM.cancel(id);
|
||||||
|
mSetForegroundArgs[0] = Boolean.FALSE;
|
||||||
|
invokeMethod(mSetForeground, mSetForegroundArgs);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCreate() {
|
||||||
|
mNM = (NotificationManager)getSystemService(NOTIFICATION_SERVICE);
|
||||||
|
app = (App)getApplication();
|
||||||
|
try {
|
||||||
|
mStartForeground = getClass().getMethod("startForeground",
|
||||||
|
mStartForegroundSignature);
|
||||||
|
mStopForeground = getClass().getMethod("stopForeground",
|
||||||
|
mStopForegroundSignature);
|
||||||
|
} catch (NoSuchMethodException e) {
|
||||||
|
// Running on an older platform.
|
||||||
|
mStartForeground = mStopForeground = null;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
mSetForeground = getClass().getMethod("setForeground",
|
||||||
|
mSetForegroundSignature);
|
||||||
|
} catch (NoSuchMethodException e) {
|
||||||
|
throw new IllegalStateException(
|
||||||
|
"OS doesn't have Service.startForeground OR Service.setForeground!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onDestroy() {
|
||||||
|
// Make sure our notification is gone.
|
||||||
|
stopForegroundCompat(R.string.service_started);
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is the old onStart method that will be called on the pre-2.0
|
||||||
|
// platform. On 2.0 or later we override onStartCommand() so this
|
||||||
|
// method will not be called.
|
||||||
|
@Override
|
||||||
|
public void onStart(Intent intent, int startId) {
|
||||||
|
handleCommand(intent);
|
||||||
|
}
|
||||||
|
|
||||||
|
//@Override
|
||||||
|
public int onStartCommand(Intent intent, int flags, int startId) {
|
||||||
|
handleCommand(intent);
|
||||||
|
// We want this service to continue running until it is explicitly
|
||||||
|
// stopped, so return sticky.
|
||||||
|
return 1; //START_STICKY;
|
||||||
|
}
|
||||||
|
|
||||||
|
void handleCommand(Intent intent)
|
||||||
|
{
|
||||||
|
if (app.isEnabled())
|
||||||
|
{
|
||||||
|
CharSequence text = getText(R.string.service_started);
|
||||||
|
|
||||||
|
Notification notification = new Notification(R.drawable.icon, text,
|
||||||
|
System.currentTimeMillis());
|
||||||
|
|
||||||
|
PendingIntent contentIntent = PendingIntent.getActivity(this, 0,
|
||||||
|
new Intent(this, Main.class), 0);
|
||||||
|
|
||||||
|
notification.setLatestEventInfo(this,
|
||||||
|
"KalSMS running",
|
||||||
|
text, contentIntent);
|
||||||
|
|
||||||
|
startForegroundCompat(R.string.service_started, notification);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
this.stopForegroundCompat(R.string.service_started);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public IBinder onBind(Intent intent) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
@ -1,12 +1,9 @@
|
|||||||
package org.envaya.kalsms;
|
package org.envaya.kalsms;
|
||||||
|
|
||||||
import android.app.IntentService;
|
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.database.ContentObserver;
|
import android.database.ContentObserver;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
final class MmsObserver extends ContentObserver {
|
final class MmsObserver extends ContentObserver {
|
||||||
|
|
||||||
|
@ -26,7 +26,6 @@ import org.apache.http.entity.mime.FormBodyPart;
|
|||||||
import org.apache.http.entity.mime.MultipartEntity;
|
import org.apache.http.entity.mime.MultipartEntity;
|
||||||
import org.apache.http.entity.mime.content.StringBody;
|
import org.apache.http.entity.mime.content.StringBody;
|
||||||
import org.apache.http.message.BasicNameValuePair;
|
import org.apache.http.message.BasicNameValuePair;
|
||||||
import org.apache.http.util.EntityUtils;
|
|
||||||
import org.envaya.kalsms.App;
|
import org.envaya.kalsms.App;
|
||||||
import org.envaya.kalsms.Base64Coder;
|
import org.envaya.kalsms.Base64Coder;
|
||||||
import org.envaya.kalsms.OutgoingMessage;
|
import org.envaya.kalsms.OutgoingMessage;
|
||||||
@ -210,6 +209,7 @@ public class HttpTask extends AsyncTask<String, Void, HttpResponse> {
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
handleResponse(response);
|
handleResponse(response);
|
||||||
|
response.getEntity().consumeContent();
|
||||||
}
|
}
|
||||||
catch (Throwable ex)
|
catch (Throwable ex)
|
||||||
{
|
{
|
||||||
@ -226,10 +226,6 @@ public class HttpTask extends AsyncTask<String, Void, HttpResponse> {
|
|||||||
|
|
||||||
protected void handleResponse(HttpResponse response) throws Exception
|
protected void handleResponse(HttpResponse response) throws Exception
|
||||||
{
|
{
|
||||||
if (response != null)
|
|
||||||
{
|
|
||||||
response.getEntity().consumeContent();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void handleFailure()
|
protected void handleFailure()
|
||||||
|
@ -102,6 +102,7 @@ public class Prefs extends PreferenceActivity implements OnSharedPreferenceChang
|
|||||||
{
|
{
|
||||||
app.log(app.isEnabled() ? "SMS Gateway started." : "SMS Gateway stopped.");
|
app.log(app.isEnabled() ? "SMS Gateway started." : "SMS Gateway stopped.");
|
||||||
app.setOutgoingMessageAlarm();
|
app.setOutgoingMessageAlarm();
|
||||||
|
app.updateEnabledNotification();
|
||||||
}
|
}
|
||||||
|
|
||||||
updatePrefSummary(findPreference(key));
|
updatePrefSummary(findPreference(key));
|
||||||
|
Loading…
Reference in New Issue
Block a user