OnHandleIntent() not called in IntentService - java

I know this question has been asked before, but I've been over all of the answers I could find and still haven't been able to solve the problem.
The issue is that when by BroadcastReceiver starts the IntentService onHandleIntent() isn't called. Weirdly enough the constructor does run (as I can see by the Log output).
This is my code:
NoLiSeA.class
(This class contains the BroadcastReceiver that starts my service)
public void toProcess(StatusBarNotification sbn) {
LocalBroadcastManager.getInstance(this).registerReceiver(notificationForwarder, new IntentFilter("to_forward"));
Intent intent = new Intent("to_forward");
intent.putExtra("sbn", sbn);
LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
Log.i("NoLiSe.TAG", "toProcess");
}
private BroadcastReceiver notificationForwarder = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
Log.i("NoLiSe.TAG", "BroadCastReceiver.onReceive");
Intent i = new Intent(context, CoreTwoA.class);
i.putExtras(intent);
startService(i);
}
}
};
CoreTwoA.class
(This is the IntentService. onHandleIntent() is not called as I can see due to no log text in the console.)
public class CoreTwoA extends IntentService {
private TextToSpeech mtts;
public CoreTwoA() {
super("TheCoreWorker");
Log.d("source", "exception", new Exception());
Log.i("CoreTwoA.TAG", "Constructor");
}
#Override
protected void onHandleIntent(Intent intent) {
Log.i("CoreTwoA.TAG", "onHandleIntent");
}
}
AndroidManifest.xml
<service
android:name=".CoreTwoA"
android:label="#string/service_name"
android:exported="false">
</service>
UPDATE
So based on discussions below, I was able to narrow down the problem to the following line of code in the BroadCastReceiver:
i.putExtra("sbn", sbn)
If I remove it, i.e. add no extras to the intent, then my the onHandleIntent() method in my IntentService does run.
If it is included, onHandleIntent() doesn't run and the following is written to logcat by the Log.d() in the Constructor of my IntentService
06-10 19:40:35.355 25094-25094/com.dezainapps.myapp D/source: exception
java.lang.Exception
at com.dezainapps.myapp.CoreTwoA.<init>(CoreTwoA.java:20)
at java.lang.Class.newInstance(Native Method)
at android.app.ActivityThread.handleCreateService(ActivityThread.java:2859)
at android.app.ActivityThread.-wrap4(ActivityThread.java)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1427)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:148)
at android.app.ActivityThread.main(ActivityThread.java:5417)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)
06-10 19:40:35.355 25094-25094/com.dezainapps.myapp I/CoreTwoA.TAG: Constructor
Any ideas why passing a StatusBarNotification object, that implements Parcelable, to a IntentService via an Intent doesn't work?
Oddly enough broadcasting the same StatusBarNotfication sbn object from my toProcess() method via an intent (see code) does work.

I had the same problem as the OP.
The issue turned out to be that I was passing a huge ArrayList (of about 4000 Parcelable elements) via the Intent that starts the IntentService. It was extremely difficult to diagnose as it failing 'silently' on a customer's device, so I got no ACRA error report.
Anyway, I used a quick and dirty trick to fix the problem - basically to store the ArrayList in a static element that I used to set/get the ArrayList rather than try to pass it through the Intent.
On further investigation (doing some tests other devices) I found a TransactionTooLargeException being thrown. More discussion on that here.
Here's my test code if anyone would like to replicate:
Test code
If you want to make it work, change the 4000 value to something much smaller.
ArrayList<ParcelableNameValuePair> testArrayList = new ArrayList<>();
for (int i = 0; i < 4000; i++) {
testArrayList.add(new ParcelableNameValuePair("name" + i, "value" + i));
}
TestIntentService.startAction(AdminHomeActivity.this, testArrayList);
TestIntentService.java
public class TestIntentService extends IntentService {
private static final String LOG_TAG = TestIntentService.class.getSimpleName();
private static final String TEST_ACTION = "com.example.action.FOO";
private static final String EXTRA_PARAM1 = "com.example.extra.PARAM1";
private static final String EXTRA_PARAM2 = "com.example.extra.PARAM2";
public TestIntentService() {
super("TestIntentService");
}
public static void startAction(Context context, ArrayList<ParcelableNameValuePair> testArrayList) {
Log.d(LOG_TAG, "1. startAction()");
Utilities.makeToast(context, "1. startAction()");
try {
int arrayListSize = (testArrayList == null) ? -1 : testArrayList.size();
Log.d(LOG_TAG, "2. arrayListSize: " + arrayListSize);
Utilities.makeToast(context, "2. arrayListSize: " + arrayListSize);
Intent intent = new Intent(context, TestIntentService.class);
intent.setAction(TEST_ACTION);
//intent.putExtra(EXTRA_PARAM1, testArrayList);
intent.putParcelableArrayListExtra(EXTRA_PARAM2, testArrayList);
/**
* This line should result in a call to onHandleIntent() but, if we're sending a huge ArrayList, it doesn't...
*/
context.startService(intent);
}
catch(Exception e) {
Log.e(LOG_TAG, "Exception starting service", e);
Utilities.makeToast(context, "Exception starting service: " + e);
}
}
#Override
protected void onHandleIntent(Intent intent) {
Log.d(LOG_TAG, "3. onHandleIntent()");
Utilities.makeToast(getApplicationContext(), "3. onHandleIntent()");
try {
if (intent != null) {
final String action = intent.getAction();
if (TEST_ACTION.equals(action)) {
ArrayList<ParcelableNameValuePair> testArrayList = intent.getParcelableArrayListExtra(EXTRA_PARAM1);
int testArrayListSize = (testArrayList == null) ? -1 : testArrayList.size();
Log.d(LOG_TAG, "4. testArrayListSize: " + testArrayListSize);
Utilities.makeToast(getApplicationContext(), "4. testArrayListSize: " + testArrayListSize);
ArrayList<ParcelableNameValuePair> testArrayList2 = intent.getParcelableArrayListExtra(EXTRA_PARAM2);
int testArrayList2Size = (testArrayList2 == null) ? -1 : testArrayList2.size();
Log.d(LOG_TAG, "5. testArrayList2Size: " + testArrayList2Size);
Utilities.makeToast(getApplicationContext(), "5. testArrayList2Size: " + testArrayList2Size);
}
}
}
catch(Exception e) {
Log.e(LOG_TAG, "Exception handling service intent", e);
Utilities.makeToast(getApplicationContext(), "Exception handling service intent: " + e);
}
}
}
ParcelableNameValuePair.java
public class ParcelableNameValuePair implements Parcelable {
private String name, value;
public ParcelableNameValuePair(String name, String value) {
this.name = name;
this.value = value;
}
public String getName() {
return name;
}
public String getValue() {
return value;
}
#Override
public int describeContents() {
return 0;
}
#Override
public void writeToParcel(Parcel out, int flags) {
out.writeString(name);
out.writeString(value);
}
public static final Parcelable.Creator<ParcelableNameValuePair> CREATOR = new Parcelable.Creator<ParcelableNameValuePair>() {
public ParcelableNameValuePair createFromParcel(Parcel in) {
return new ParcelableNameValuePair(in);
}
public ParcelableNameValuePair[] newArray(int size) {
return new ParcelableNameValuePair[size];
}
};
private ParcelableNameValuePair(Parcel in) {
name = in.readString();
value = in.readString();
}
}
Like I say, I used a quick and dirty solution to get around this problem. I think a better solution would be for the app to write the ArrayList to the file system, then pass a reference to that file (e.g., filename/path) via the Intent to the IntentService and then let the IntentService retrieve the file contents and convert it back to an ArrayList.
When the IntentService has done with the file, it should either delete it or pass the instruction back to the app via a Local Broadcast to delete the file that it created (passing back the same file reference that was supplied to it).

Have you tried using context.startService(intent);?
When you're in a broadcast receiver like this you don't have a context of your own to reference I believe so you need to use the one passed to the onRecieve method.

Use this:
private BroadcastReceiver notificationForwarder = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
Log.i("NoLiSe.TAG", "BroadCastReceiver.onReceive");
Intent i = new Intent(context, CoreTwoA.class);
i.putExtra("intent",intent);
context.startService(i);
}
}
};

Use below code:
private BroadcastReceiver notificationForwarder = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
Log.e("NoLiSe.TAG", "BroadCastReceiver.onReceive");
Intent i = new Intent(context, CoreTwoA.class);
i.putExtra("sbn",intent.getParcelableExtra("sbn"));
startService(i);
}
};
You are incorrectly using i.putExtras(intent); which I removed and added other way of sending the StatusBarNotification object through putExtra.
I tested this code and does call onHandleIntent

Related

How to make activity to show data got from the service?

I need write a service which will update the list in MainActivity every 30sec. I use MVVM with ViewModel and LiveData and so my Service class looks like this:
public class ArticleJobService extends JobService {
public static String TAG = "ArticleJobService";
private Context context = this;
#Override
public boolean onStartJob(JobParameters jobParameters) {
Log.d(TAG, "onStartJob");
MainActivity.PAGE_NUMBER++;
LiveData<List<Article>> liveArticles = ArticleRepository.getInstance(getApplication()).getArticles(MainActivity.PAGE_NUMBER);
liveArticles.observeForever(new Observer<List<Article>>() {
#Override
public void onChanged(#Nullable List<Article> articles) {
Log.d(TAG, "onStartJob - onChanged!!!!!!");
liveArticles.removeObserver(this);
NotificationUtils.showNotification(context, articles.get(0).getSectionName(), articles.get(0).getWebTitle());
jobFinished(jobParameters, true);
}
});
return true;
}
}
Class for my notification:
public static void showNotification(Context context, String section, String title) {
PendingIntent contentPendingIntent = PendingIntent.getActivity
(context, REQUEST_CODE, new Intent(context, MainActivity.class),
PendingIntent.FLAG_UPDATE_CURRENT);
NotificationManager manager =
(NotificationManager) context.getSystemService(NOTIFICATION_SERVICE);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
manager.createNotificationChannel(createNotificationChannel(context));
}
NotificationCompat.Builder builder = new NotificationCompat.Builder(context, CHANNEL_ID)
.setContentTitle(section)
.setContentText(title)
.setContentIntent(contentPendingIntent)
.setSmallIcon(R.drawable.app_icon)
.setPriority(NotificationCompat.PRIORITY_HIGH)
.setDefaults(NotificationCompat.DEFAULT_ALL)
.setAutoCancel(true);
manager.notify(0, builder.build());
}
When Onchanged in JobService works I get the list and show a notification. Notification opens MainActivity which makes new call to api as it always did. What changes do I have to make in order the MainActivity to show the list that I got from the service??? I really can't tie this up together.
I heard of IPC but wouldn't do that, I want some simpler practice which I sure exists which I just don't know about.
Also, there are two cases: Notification came and MainActivity is open, app is open but MainActivity is not in the foreground and app is on the background or closed. How should I handle each of these cases?
See also piece of code from MainActivity onCreate:
mArticleViewModel = ViewModelProviders.of(this).get(ArticleViewModel.class);
mArticleViewModel.getArticleList(PAGE_NUMBER).observe(this, articles -> {
Log.d(TAG, "List<Result> onChanged!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
mProgressBar.setVisibility(View.GONE);
mProgressBarMain.setVisibility(View.GONE);
mIsLoading = false;
mArticles = articles;
Please provide the best practices for this task, I know it's very common I just do it first time and using LiveData makes it way more complicated.
Here is Also Repository code:
public static ArticleRepository getInstance(Application application){
if(INSTANCE == null){
return new ArticleRepository(application);
}
return INSTANCE;
}
private ArticleRepository(Application application) {
Log.d(TAG, "ArticleRepository constructor");
mContext = application;
mArticles = new MutableLiveData<>();
ArticleRoomDatabase db = ArticleRoomDatabase.getInstance(application);
mArticleDao = db.articleDao();
}
public LiveData<List<Article>> getArticles(int page) {
Log.d(TAG, "getArticles");
if (NetworkUtils.isOnline(mContext)) {
Log.d(TAG, "isOnline");
mArticles = loadFromNetwork(page);
} else {
Log.d(TAG, "is NOT Online");
mArticles = loadFromDB(page);
}
}
You have this problem specifically because your Repository implementation is incorrect.
public LiveData<List<Article>> getArticles(int page) {
Log.d(TAG, "getArticles");
if (NetworkUtils.isOnline(mContext)) {
Log.d(TAG, "isOnline");
mArticles = loadFromNetwork(page);
} else {
Log.d(TAG, "is NOT Online");
mArticles = loadFromDB(page);
}
}
If you check the code for NetworkBoundResource, the trick is that you have a single LiveData that binds together the ability to both load from network, and to load from database.
In your case, you are replacing the database's auto-updating query results whenever you have network access - which is why you can't update the MainActivity.
The easiest way (without using a MediatorLiveData) is to have two separate functions on Repository: one for fetchFromNetwork, and one for fetchFromDatabase. The MainActivity should always fetch from database, while the Service always triggers load from network (and inserts it directly into database via a Dao).
This way, the observe function in MainActivity will receive the latest data when Service inserts the data into DB on background thread.

One Service data Multiple Activity in android

Hi I make Android application for Xamarin. I have created a simple application in the Android studio. so any answer welcome either Java or C#
I have a service(GPS service) and 2 Activities.
MainActivity - GPS service are well connected with the broadcast. I hope MainActivity -> Another activity real time GPS point.(It is also okay to send from the GPS service to another activity.) but it is fail...app is dead..
MainActivity code
private void RegisterService()
{
_gpsServiceConnection = new GPSServiceConnection(_binder);
_gpsServiceIntent = new Intent(Android.App.Application.Context, typeof(GPS.GPSService));
BindService(_gpsServiceIntent, _gpsServiceConnection, Bind.AutoCreate);
}
private void RegisterBroadcastReceiver()
{
IntentFilter filter = new IntentFilter(GPSServiceReciever.LOCATION_UPDATED);
filter.AddCategory(Intent.CategoryDefault);
_receiver = new GPSServiceReciever();
RegisterReceiver(_receiver, filter);
}
private void UnRegisterBroadcastReceiver()
{
UnregisterReceiver(_receiver);
}
public void UpdateUI(Intent intent)
{
LatLng_txt.Text = intent.GetStringExtra("Location");
Lat = intent.GetDoubleExtra("Lat", 0.0);
Lng = intent.GetDoubleExtra("Lng", 0.0);
}
protected override void OnResume()
{
base.OnResume();
RegisterBroadcastReceiver();
}
protected override void OnPause()
{
base.OnPause();
UnRegisterBroadcastReceiver();
}
[BroadcastReceiver]
internal class GPSServiceReciever : BroadcastReceiver
{
public static readonly string LOCATION_UPDATED = "LOCATION_UPDATED";
public override void OnReceive(Context context, Intent intent)
{
if (intent.Action.Equals(LOCATION_UPDATED))
{
Instance.UpdateUI(intent);
}
}
}
GPS Service code
public void OnLocationChanged(Location location)
{
try
{
_currentLocation = location;
if (_currentLocation == null)
{
_location = "Unable to determine your location.";
}
else
{
_location = String.Format("{0}, {1}", _currentLocation.Latitude, _currentLocation.Longitude);
Geocoder geocoder = new Geocoder(this);
IList<Address> addressList = geocoder.GetFromLocation(_currentLocation.Latitude,
_currentLocation.Longitude, 10);
Address addressCurrent = addressList.FirstOrDefault();
if (addressCurrent != null)
{
StringBuilder deviceAddress = new StringBuilder();
for (int i = 0; i < addressCurrent.MaxAddressLineIndex; i++)
{
deviceAddress.Append(addressCurrent.GetAddressLine(i)).AppendLine(",");
}
_address = deviceAddress.ToString();
}
else
{
_address = "Unable to determine the address.";
}
IList<Address> source = geocoder.GetFromLocationName(_sourceAddress, 1);
Address addressOrigin = source.FirstOrDefault();
var coord1 = new LatLng(addressOrigin.Latitude, addressOrigin.Longitude);
var coord2 = new LatLng(addressCurrent.Latitude, addressCurrent.Longitude);
var distanceInRadius = Utils.HaversineDistance(coord1, coord2, Utils.DistanceUnit.Miles);
_remarks = string.Format("Your are {0} miles away from your original location.", distanceInRadius);
Intent intent = new Intent(this, typeof(MainActivity.GPSServiceReciever));
intent.SetAction(MainActivity.GPSServiceReciever.LOCATION_UPDATED);
intent.AddCategory(Intent.CategoryDefault);
intent.PutExtra("Location", _location);
intent.PutExtra("Lat", _currentLocation.Latitude);
intent.PutExtra("Lng", _currentLocation.Longitude);
SendBroadcast(intent);
}
}
catch
{
_address = "Unable to determine the address.";
}
}
Is not there a good way?
I understood your problem.But dont know more about GPS etc.I have faced the same problem when I was creating Music App.
Two activities were there and one service.And successfully got real time song position and song data from both activities.
My MainActivity has
ServiceConnection sc=null;
public static PlayerService ps;
And gets its value in onCreate of MainActivity
sc=new ServiceConnection(){
#Override
public void onServiceConnected(ComponentName p1, IBinder p2)
{
PlayerService.Getters getters=(PlayerService.Getters) p2;
ps=getters.getService();
}
#Override
public void onServiceDisconnected(ComponentName p1)
{
// TODO: Implement this method
}
};
Then PlayerService.Getters class is
public class Getters extends Binder
{
public PlayerService getService()
{
return PlayerService.this;
}
}
PlayerService has
#Override
public IBinder onBind(Intent p1)
{
return new Getters();
}
getService of Getters gives the object of PlayerService to my MainActivity.
Now I can get real time values of service variables and methods using static ps from multiple activities.
In order to send data or information from Service to Activity, you'll need to use Messenger API. This API will allow you to create an inter process communication (IPC) i.e. a communication link between two or more processes. In Android, Activity and Service are two separate processes, so you can use the IPC technique to establish a communication link in between them.
In the IPC technique, there are two ends, the Server end and the Client end. The Service acts as the Server and Activity acts as the Client.
Note: Service will only be able to communicate with one Activity at a time.
Messenger allows for the implementation of message-based communication across processes by help of Handlers.
Handler is a that allows you to send and process these messages.
Steps for implementing a Messenger:
Step 1. Service implements a Handler which receives the callbacks from the Activity
Step 2. The Handler then creates a Messenger object which further on creates an IBinder that the Service returns to the Activity.
Step 3. Activity then uses the IBinder to instantiate the Messenger, which the Activity uses to send messages to the Service.
Step 4. The Service receives the messages in the Handler created in the 1st step.
Lets now understand it with an example:
Create a Handler in the Service like this:
class ServiceHandler extends Handler {
#Override
public void handleMessage(Message msg) {
switch (msg.what) {
default:
super.handleMessage(msg);
}
}
}
Now, add the Messenger object along with onBind() method to the Service as mentioned in 2nd step above:
final Messenger messenger = new Messenger(new ServiceHandler());
#Override
public IBinder onBind(Intent intent) {
return messenger.getBinder();
}
In the Activity, we will create a ServiceConnection to fetch the iBinder from the Service to instantiate the Messenger object as mentioned in the 3rd step above.
Messenger messenger;
private ServiceConnection serviceConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName className, IBinder iBinder) {
messenger = new Messenger(iBinder);
}
public void onServiceDisconnected(ComponentName className) {
}
};
Bind the Service to the Activity by help of the ServiceConnection created above:
bindService(new Intent(this, MessengerService.class), serviceConnection,
Context.BIND_AUTO_CREATE);
To send messages to the Service from the Activity, use the send() method of the Messenger object.
If you want to receive messages from the Service in the Activity, you need to create a Messenger in the Activity along with a Handler and use the replyTo parameter of the Messenger to receive messages to the respective Handler.

Adobe Air ANE for android with java native extension trying to receive broadcast

I'm trying to create a native extension which can receive broadcasts, sent from a native android am as intent broadcasts.
The sending part works, I've tested this with a native app that has a broadcast receiver, but I cant get it to work in the native extension.
Here's what I have so far:
Here the java side of the ANE
public class ReceiverPhidget extends BroadcastReceiver {
private FREContext mFREContext;
public ReceiverPhidget(FREContext mFREContext) {
this.mFREContext = mFREContext;
}
#Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (action.equals(IntentsKeys.INTENT_PHIDGET_CONNECTED)){
//Send listener in ANE project with message that phidget connected (not must)
System.out.println("Phidget connected");
mFREContext.dispatchStatusEventAsync("Yes", Keys.KEY_CONNECTED);
} else
if (action.equals(IntentsKeys.INTENT_PHIDGET_DISCONNECTED)){
//Send listener in ANE project with message that phidget disconnected (not must)
System.out.println("Phidget disconnected");
mFREContext.dispatchStatusEventAsync("Yes", Keys.KEY_DISCONNECTED);
} else
if (action.equals(IntentsKeys.INTENT_PHIDGET_GAIN_TAG)){
//Send listener with data in ANE project with message that phidget gain receive
String message = intent.getStringExtra(IntentsKeys.INTENT_PHIDGET_EXTRA_DATA);
System.out.println("Phidget gain message: " + message);
Log.d("TAG FOUND", message);
mFREContext.dispatchStatusEventAsync(message, Keys.KEY_TAG_GAIN);
}
}
public static IntentFilter getIntentFilter(){
final IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(IntentsKeys.INTENT_PHIDGET_CONNECTED);
intentFilter.addAction(IntentsKeys.INTENT_PHIDGET_DISCONNECTED);
intentFilter.addAction(IntentsKeys.INTENT_PHIDGET_GAIN_TAG);
return intentFilter;
}
}
And the FREExtension
public class ReceiverExtension implements FREExtension {
private ReceiverPhidget mReceiverPhidget;
private ReceiverExtensionContext mContext;
#Override
public void initialize() {
mReceiverPhidget = new ReceiverPhidget(mContext);
mContext.getActivity().registerReceiver(mReceiverPhidget, ReceiverPhidget.getIntentFilter());
}
#Override
public FREContext createContext(String s) {
return mContext = new ReceiverExtensionContext();
}
#Override
public void dispose() {
mContext.getActivity().unregisterReceiver(mReceiverPhidget);
}
}
And here is the flash library side of the ANE
package nl.mediaheads.anetest.extension {
import flash.events.EventDispatcher;
import flash.events.StatusEvent;
import flash.external.ExtensionContext;
public class RFIDController extends EventDispatcher {
private var extContext:ExtensionContext;
private var channel:int;
private var scannedChannelList:Vector.<int>;
public function RFIDController() {
extContext = ExtensionContext.createExtensionContext(
"nl.mediaheads.anetest.exntension.RFIDController", "");
extContext.addEventListener(StatusEvent.STATUS, onStatus);
}
private function onStatus(event:StatusEvent):void {
if (event.level == EventKeys.KEY_TAG_GAIN) {
dispatchEvent (new TagEvent(TagEvent.TAG_GAINED, event.code) );
}
}
}
}
And here is my test mobile project class to test the ANE
package
{
import flash.display.Sprite;
import flash.display.StageAlign;
import flash.display.StageScaleMode;
import flash.events.Event;
import flash.text.TextField;
import nl.mediaheads.anetest.extension.RFIDController;
[SWF(width="1280", height="800", frameRate="60", backgroundColor="#ffffff")]
public class AneTestApp extends Sprite
{
private var tf:TextField;
private var rc:RFIDController;
public function AneTestApp()
{
super();
// support autoOrients
stage.align = StageAlign.TOP_LEFT;
stage.scaleMode = StageScaleMode.NO_SCALE;
stage.color = 0xFFFFFF;
addEventListener(Event.ADDED_TO_STAGE, onAdded);
}
private function onAdded(event:Event):void {
//
tf = new TextField();
tf.width = 200;
tf.height = 50;
tf.x = 10;
tf.y = 64;
tf.mouseEnabled = false;
tf.background = true;
tf.backgroundColor = 0xF50000;
addChild(tf);
rc = new RFIDController();
tf.text = "test 1";
this.addEventListener( TagEvent.TAG_GAINED , onTagAdded);
tf.text = "test 2";
//
}
private function onTagAdded(event:TagEvent):void
{
tf.text = event.params;
}
}
}
I have signed the ANE accordingly, I also signed the test app it's self.
I have a Log.d in the java part of the ANE which should pop up on log cat but it doesn't, also the textfield just becomes blank as soon as I initialized the RFIDController even without added the event listener.
If you need any more code or information to help me solve this problem feel free to ask.
I could really use some help because I'm completely lost, I've followed multiple tutorials and guide on how to do this, I should have done everything correctly, but I clearly have not.
UPDATE: 1
The extension xml
<extension xmlns="http://ns.adobe.com/air/extension/3.5">
<id>nl.mediaheads.anetest.exntension.RFIDController</id>
<versionNumber>0.0.1</versionNumber>
<platforms>
<platform name="Android-ARM">
<applicationDeployment>
<nativeLibrary>AneTest.jar</nativeLibrary>
<initializer>nl.mediaheads.anetest.ReceiverExtension</initializer>
<finalizer>nl.mediaheads.anetest.ReceiverExtension</finalizer>
</applicationDeployment>
</platform>
</platforms>
</extension>
UPDATE 2:
I fixed it, it was an context issue together with that flash somehow clean my custom event so I used status event to parse from the flash side of the ANE to the air application itself.
Currently you are creating your receiver at the initialisation point of the extension which will most likely be called before the context creation, so your context may be null at that point and causing your errors.
Try moving the creation of your ReceiverPhidget to the constructor of your ReceiverExtensionContext. Something like the following (I haven't tested this):
public class ReceiverExtensionContext extends FREContext
{
private ReceiverPhidget mReceiverPhidget;
public ReceiverExtensionContext()
{
mReceiverPhidget = new ReceiverPhidget( this );
getActivity().registerReceiver( mReceiverPhidget, ReceiverPhidget.getIntentFilter() );
}
#Override
public Map<String, FREFunction> getFunctions()
{
Map<String, FREFunction> functionMap = new HashMap<String, FREFunction>();
return functionMap;
}
#Override
public void dispose()
{
getActivity().unregisterReceiver( mReceiverPhidget );
}
}

Browser ContentObserver not being called even using different URI's

My ContentObserver for observing the history in the browser is not being called. I don't understand why it isn't. I'm not doing anything different or bizarre, I'm following the API specs exactly, but to no avail! Below is my code:
In my service:
public class MonitorService extends Service {
//some global variables declared here
private ContentObserver historyObserver, searchObserver, chromeObserver;
public void onCreate() {
super.onCreate();
isRunning = false;
this.preferences = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
//this.historyObserver = new HistoryObserver();
this.historyObserver = new HistoryObserver(new Handler());
this.searchObserver = new HistoryObserver(new Handler());
this.chromeObserver = new HistoryObserver(new Handler());
getApplicationContext().getContentResolver().registerContentObserver(Uri.parse("content://com.android.chrome.browser/history"), false, this.chromeObserver);
getApplicationContext().getContentResolver().registerContentObserver(android.provider.Browser.BOOKMARKS_URI, false, this.historyObserver);
getApplicationContext().getContentResolver().registerContentObserver(android.provider.Browser.SEARCHES_URI, false, this.searchObserver);
}
//Other required methods in class
}//end of class
Then in my HistoryObserver Class we have:
public class HistoryObserver extends ContentObserver {
public final String TAG = "HistoryObserver";
public HistoryObserver(Handler handler) {
super(handler);
Log.d(TAG, "Creating new HistoryObserver");
}
public HistoryObserver() {
super(null);
Log.d(TAG, "Creating a new HistoryObserver without a Handler");
}
#Override
public boolean deliverSelfNotifications() {
Log.d(TAG, "delivering self notifications");
return true;
}
#Override
public void onChange(boolean selfChange) {
super.onChange(selfChange);
Log.d(TAG, "onChange without uri: " + selfChange);
//onChange(selfChange, null);
}
public void onChange(boolean selfChange, Uri uri) {
super.onChange(selfChange, uri);
Log.d(TAG, "onChange: " + selfChange + "\t " + uri.toString());
}
}
Like I said there is nothing special or unique about this implementation. Yet, when I go go to a new website or search for something in Chrome, the onChange method is never fired.
I figured out the problem. The /history content provider isn't an observable. The observables come through the /bookmark uri. Once I discovered that, things got working very quickly and very well.

How do I send extra data through an urbanairship push notification

So I need to send a push notification to a user's device. Then when the user clicks on the notification, I need my app to take a specific action. I want to include the parameter for the action in the notification. But I don't want the user to see the parameter; they should just see the message. Doing some research, I found the following on the urban airship website
{
"audience": "all",
"notification": {
"alert": "Extras example",
"android": {
"extra": {
"url": "http://example.com",
"story_id": "1234",
"moar": "{\"key\": \"value\"}"
}
}
},
"device_types": ["android"]
}
So I am supposing that the alert portion is what a user sees. And that the portion under android could be the parameters. So my question is, in Java, how do I read those extra portions? such as story_id, or moar?
Since there is no answer accepted here I thought I'll show how I am doing it.
I have a class that extends BroadcastReceiver like you should if you are following UrbanAirship. In this class I recieve the notifications:
public class IntentReceiver extends BroadcastReceiver {
private static final String logTag = "PushUA";
private String pushToken;
public static String APID_UPDATED_ACTION_SUFFIX = ".apid.updated";
#Override
public void onReceive(Context context, Intent intent) {
Log.i(logTag, "Received intent: " + intent.toString());
String action = intent.getAction();
if (action.equals(PushManager.ACTION_PUSH_RECEIVED)) {
int id = intent.getIntExtra(PushManager.EXTRA_NOTIFICATION_ID, 0);
logPushExtras(intent);
} else if (action.equals(PushManager.ACTION_NOTIFICATION_OPENED)) {
Log.i(logTag, "User clicked notification. Message: " + intent.getStringExtra(PushManager.EXTRA_ALERT));
logPushExtras(intent);
String url= intent.getStringExtra("url"); //Here you get your extras
...
Might help someone:)
You can extend BasicPushNotificationBuilder and override buildNotification. That method gets the extra parameters in extras.
#Override
public Notification buildNotification(String alert, Map<String, String> extras) {
// Only build inbox style notification for rich push messages
if (extras != null && RichPushManager.isRichPushMessage(extras)) {
return createRichNotification(alert);
} else {
return super.buildNotification(alert, extras);
}
}
See docs here.
Eran had the right idea, but you actually want to implement PushNotificationBuilder and then override buildNotification().
Something like this:
/**
* This class encapsulates notifications (those that appear in the notification shade).
*
* #author Karim Varela
*/
public class ManagerNotifications implements PushNotificationBuilder
{
#Override
public Notification buildNotification(String alert, Map<String, String> extras)
{
return null;
}
#Override
public int getNextId(String alert, Map<String, String> extras)
{
return 0;
}
}

Categories

Resources