I built a fully-functioning FragmentActivity based on this demo.
Originally (like other activities in my app) the data was being loaded into the FragmentActivity.ListFragment.ListView from SQLite in the UI thread.
I have successfully converted two other activities (not fragment- or list-activities) to a ResultReceiver paradigm that uses an IntentService to get the data from SQLite. The obvious difference in this instance is the fact that the custom ResultReceiver is declared in the ListFragment, not the FragmentActivity:
public EWTRReceiver ArrayListFragmentReceiver;
PROBLEM: The IntentService gets the request, pulls the data but is NOT able to get the data back to the ListFragment: NullPointerException on this line in IntentService.rspPlayers():
r.send(mSignal, resultData);
I'm convinced that I'm missing something simple that will make me feel like an idiot...i just need to be pushed in the right direction.
Following is (1) the call from the ListFragment to the IntenService, (2) the onHandleIntent of the IntentService and (3) the method in the IntentService that calls back to the ListFragment (rspPlayers()).
Thanks!
FragmentActivity.ListFragment.callCtlr():
private void callCtlr(int mSignal){
if (BuildConfig.DEBUG) {
Log.i(Constants.TAG_FRGACTPLAYERS, "ArrayListFragment.callCtlr() called with signal: "+mSignal);
}
/** Intent to transmit between processes */
Intent intent = new Intent(getActivity(), CtlPlayers.class);
// declare Source of Signal
intent.putExtra("Source", ArrayListFragmentReceiver);
/** process signal to send to CtlPlayers */
switch (mSignal){
case Constants.S_DB_READPLYRLDR:
if (BuildConfig.DEBUG) {
Log.i(Constants.TAG_FRGACTPLAYERS, "ArrayListFragment.callCtlr(S_DB_READPLYRLDR) to CtlPlayers.");
}
// Send CtlAlliances the request for the list of Alliances in current Sector
intent.putExtra("CurrentSector", this.getArguments().getString("FSECTR"));
intent.putExtra("CurrentAlliance", this.getArguments().getString("FANAME"));
intent.putExtra("signal", Constants.S_DB_READPLYRLDR);
break;
case Constants.S_DB_READPLYRREC:
if (BuildConfig.DEBUG) {
Log.i(Constants.TAG_FRGACTPLAYERS, "ArrayListFragment.callCtlr(S_DB_READPLYRREC) to CtlPlayers.");
}
// Send CtlAlliances the request for the list of Alliances in current Sector
intent.putExtra("CurrentSector", this.getArguments().getString("FSECTR"));
intent.putExtra("CurrentAlliance", this.getArguments().getString("FANAME"));
intent.putExtra("signal", Constants.S_DB_READPLYRREC);
break;
default:
//do nothing
break;
}
getActivity().startService(intent);
}
IntentService.onHandleIntent():
protected void onHandleIntent(Intent intentREQ) {
if (BuildConfig.DEBUG) {
Log.i(Constants.TAG_CTLPLAYERS, "onHandleIntent(Intent intent) called.");
}
/** get the receiver and bundle from the incoming Intent */
ResultReceiver rInComing = intentREQ.getParcelableExtra("Source");
/** get the bundle from the incoming Intent */
extras = intentREQ.getExtras();
/** variable to convey results to ActDlgAddPlyr */
boolean mAnswer = false;
/** tracks ActSector's context */
Context mCtx = getApplicationContext();
int mSignal = intentREQ.getIntExtra("signal", Constants.R_NO_SIGNAL);
if (BuildConfig.DEBUG) {
Log.i(Constants.TAG_CTLPLAYERS, "Signal Received = " + mSignal);
}
switch (mSignal) {
case Constants.R_NO_SIGNAL :
if (BuildConfig.DEBUG) {
Log.i(Constants.TAG_CTLPLAYERS, "onHandleIntent(): NO READABLE SIGNAL WAS RECEIVED!");
}
break;
case Constants.S_DB_ADDPLYR :
if (BuildConfig.DEBUG) {
Log.i(Constants.TAG_CTLPLAYERS, "onHandleIntent(): S_DB_ADDPLYR received.");
}
synchronized (this) {
// Get the New Sector Name from the bundle
if (BuildConfig.DEBUG) {
Log.i(Constants.TAG_CTLPLAYERS, "onHandleIntent(): S_DB_ADDPLYR received with New Player.");
}
mAnswer = addNewPlayer(mCtx, extras);
rspPlayers(Constants.R_DB_ADDPLYR, mAnswer, rInComing);
}
break;
case Constants.S_DB_READPLYRLDR :
if (BuildConfig.DEBUG) {
Log.i(Constants.TAG_CTLPLAYERS, "onHandleIntent(): S_DB_READPLYRLDR received.");
}
synchronized (this) {
// Get the New Sector Name from the bundle
if (BuildConfig.DEBUG) {
Log.i(Constants.TAG_CTLPLAYERS, "onHandleIntent(): S_DB_READPLYRLDR received.");
}
mAnswer = readPlyrLdr(mCtx, extras);
rspPlayers(Constants.R_DB_READPLYRLDR, mAnswer, rInComing);
}
break;
case Constants.S_DB_READPLYRREC :
if (BuildConfig.DEBUG) {
Log.i(Constants.TAG_CTLPLAYERS, "onHandleIntent(): S_DB_READPLYRREC received.");
}
synchronized (this) {
// Get the New Sector Name from the bundle
if (BuildConfig.DEBUG) {
Log.i(Constants.TAG_CTLPLAYERS, "onHandleIntent(): S_DB_READPLYRREC received.");
}
mAnswer = readPlyrRec(mCtx, extras);
rspPlayers(Constants.R_DB_READPLYRREC, mAnswer, rInComing);
}
break;
} // end switch
}
IntentService.rspPlayers() [sends result back to FragmentActivity.ListFragment]:
private void rspPlayers(int mSignal, boolean mCode, ResultReceiver r) {
if (BuildConfig.DEBUG) {
Log.i(Constants.TAG_CTLPLAYERS, "respPlayers() called with signal, code: "+mSignal+", "+mCode);
}
Bundle resultData = new Bundle();
switch (mSignal) {
case Constants.R_DB_ADDPLYR :
if (mCode == true) {
resultData.putInt("reqStatus", Constants.R_TRUE_THAT);
} else {
resultData.putInt("reqStatus", Constants.R_NO_WAY);
}
break;
case Constants.R_DB_READPLYRLDR :
if (mCode == true) {
resultData.putInt("reqStatus", Constants.R_TRUE_THAT);
resultData.putInt("NumLdrRows", NumLdrRows);
resultData.putSerializable("LPlyrList", LPlyrArray);
} else {
resultData.putInt("reqStatus", Constants.R_NO_WAY);
}
break;
case Constants.R_DB_READPLYRREC :
if (mCode == true) {
resultData.putInt("reqStatus", Constants.R_TRUE_THAT);
resultData.putInt("NumRecRows", NumRecRows);
resultData.putSerializable("RPlyrList", RPlyrArray);
} else {
resultData.putInt("reqStatus", Constants.R_NO_WAY);
}
break;
default :
// do nothing
break;
}
try {
r.send(mSignal, resultData);
} catch (java.lang.Exception e) {
Log.e(Constants.TAG_CTLPLAYERS, "rspPlayers(): Exception message: "+e.getMessage());
Log.e(Constants.TAG_CTLPLAYERS, "rspPlayers(): Exception cause: "+e.getCause());
e.printStackTrace();
}
}
I think ArrayListFragmentReceiver is null.
Handler handler = new Handler();
public EWTRReceiver ArrayListFragmentReceiver = new ResultReceiver(handler)
The handler is needed to make sure the response comes back in the original thread. This would be the next crash otherwise.
Check this tutorial for a sample implementation:
http://ramdroid.github.io/androiddev/ResultReceiverDemo.html
Related
I'm developing an app that will only be used in house for testing purpose. I have searched a lot and tried different suggestions as suggested in different post but none seems to be working for me.
I'm open to any suggestions like Reflections, Accessibility Service, root or any other hack. Please help.
Regards
TRY THIS
Set all required permission in manifest.xml file.
Call this class in Service
public class PhoneListener extends PhoneStateListener {
private static PhoneListener instance = null;
/**
* Must be called once on app startup
*
* #param context - application context
* #return
*/
public static PhoneListener getInstance(Context context) {
if (instance == null) {
instance = new PhoneListener(context);
}
return instance;
}
public static boolean hasInstance() {
return null != instance;
}
private final Context context;
private CallLog phoneCall;
private PhoneListener(Context context) {
this.context = context;
}
AtomicBoolean isRecording = new AtomicBoolean();
AtomicBoolean isWhitelisted = new AtomicBoolean();
/**
* Set the outgoing phone number
* <p/>
* Called by {#link MyCallReceiver} since that is where the phone number is available in a outgoing call
*
* #param phoneNumber
*/
public void setOutgoing(String phoneNumber) {
if (null == phoneCall)
phoneCall = new CallLog();
phoneCall.setPhoneNumber(phoneNumber);
phoneCall.setOutgoing();
// called here so as not to miss recording part of the conversation in TelephonyManager.CALL_STATE_OFFHOOK
isWhitelisted.set(Database.isWhitelisted(context, phoneCall.getPhoneNumber()));
}
#Override
public void onCallStateChanged(int state, String incomingNumber) {
super.onCallStateChanged(state, incomingNumber);
switch (state) {
case TelephonyManager.CALL_STATE_IDLE: // Idle... no call
if (isRecording.get()) {
RecordCallService.stopRecording(context);
phoneCall = null;
isRecording.set(false);
}
break;
case TelephonyManager.CALL_STATE_OFFHOOK: // Call answered
if (isWhitelisted.get()) {
isWhitelisted.set(false);
return;
}
if (!isRecording.get()) {
isRecording.set(true);
// start: Probably not ever usefull
if (null == phoneCall)
phoneCall = new CallLog();
if (!incomingNumber.isEmpty()) {
phoneCall.setPhoneNumber(incomingNumber);
}
// end: Probably not ever usefull
RecordCallService.sartRecording(context, phoneCall);
}
break;
case TelephonyManager.CALL_STATE_RINGING: // Phone ringing
// DO NOT try RECORDING here! Leads to VERY poor quality recordings
// I think something is not fully settled with the Incoming phone call when we get CALL_STATE_RINGING
// a "SystemClock.sleep(1000);" in the code will allow the incoming call to stabilize and produce a good recording...(as proof of above)
if (null == phoneCall)
phoneCall = new CallLog();
if (!incomingNumber.isEmpty()) {
phoneCall.setPhoneNumber(incomingNumber);
// called here so as not to miss recording part of the conversation in TelephonyManager.CALL_STATE_OFFHOOK
isWhitelisted.set(Database.isWhitelisted(context, phoneCall.getPhoneNumber()));
}
break;
}
}
}
And use Broadcast Receiver
public class MyCallReceiver extends BroadcastReceiver {
public MyCallReceiver() {
}
static TelephonyManager manager;
#Override
public void onReceive(Context context, Intent intent) {
Log.i("JLCreativeCallRecorder", "MyCallReceiver.onReceive ");
if (!AppPreferences.getInstance(context).isRecordingEnabled()) {
removeListener();
return;
}
if (Intent.ACTION_NEW_OUTGOING_CALL.equals(intent.getAction())) {
if (!AppPreferences.getInstance(context).isRecordingOutgoingEnabled()) {
removeListener();
return;
}
PhoneListener.getInstance(context).setOutgoing(intent.getStringExtra(Intent.EXTRA_PHONE_NUMBER));
} else {
if (!AppPreferences.getInstance(context).isRecordingIncomingEnabled()) {
removeListener();
return;
}
}
// Start Listening to the call....
if (null == manager) {
manager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
}
if (null != manager)
manager.listen(PhoneListener.getInstance(context), PhoneStateListener.LISTEN_CALL_STATE);
}
private void removeListener() {
if (null != manager) {
if (PhoneListener.hasInstance())
manager.listen(PhoneListener.getInstance(null), PhoneStateListener.LISTEN_NONE);
}
}
}
I hope you get some help from this code.
Thanks
You can use accessibility events to detect the call duration and from that you can detect if the outgoing call is answered or not..
I have answered it in detail in Here` you can check that.
You need this permission in manifest
<uses-permission android:name="android.permission.READ_PHONE_STATE"/>
TelephonyManager has a listener to get phone state. implement this tho know if the phone is ringing or in a call.
TelephonyManager telephonyManager = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
PhoneStateListener callStateListener = new PhoneStateListener() {
public void onCallStateChanged(int state, String incomingNumber) {
// TODO React to a incoming call.
try {
if (state == TelephonyManager.CALL_STATE_RINGING) {
Toast.makeText(getApplicationContext(), "Phone Is Ringing" + incomingNumber, Toast.LENGTH_LONG).show();
number = incomingNumber;
//g.setPhoneNo(incomingNumber);
AndroidNetCommunicationClientActivity.mMsgSendRequest("CommandMsgCallIncoming" + number);
} else if (state == TelephonyManager.CALL_STATE_OFFHOOK) {
Toast.makeText(getApplicationContext(), "Phone is Currently in A call" + incomingNumber, Toast.LENGTH_LONG).show();
//number = mIntent.getStringExtra(Intent.EXTRA_PHONE_NUMBER);
number = incomingNumber;
} else if (state == TelephonyManager.DATA_DISCONNECTED) {
number = "";
CallID = "";
}
} catch (Exception e) {
// TODO Auto-generated catch block
//conn.MessageBox(MainActivity.this, e.getMessage());
e.printStackTrace();
}
super.onCallStateChanged(state, incomingNumber);
}
};
telephonyManager.listen(callStateListener, PhoneStateListener.LISTEN_CALL_STATE);
I wrote a custom plugin to read blocks of data from an NfcA(i.e.non-ndef) tag. It seems to work fine , but only after the second scan. I am using Activity intent to derive the "NfcAdapter.EXTRA_TAG" to later use it for reading the values. I am also updating the Intents in onNewIntent(). OnNewIntent gets called after the second scan and after that I get result all the time.But in the first scan onNewIntent does not gets called, hence I end up using the Activity tag that does not have "NfcAdapter.EXTRA_TAG", hence I get null. Please see the my code below.
SE_NfcA.java(my native code for plugin)
#Override
public boolean execute(String action, JSONArray args, CallbackContext callbackContext) throws JSONException {
String Result = "";
String TypeOfTalking = "";
if (action.contains("TalkToNFC"))
{
JSONObject arg_object = args.getJSONObject(0);
TypeOfTalking = arg_object.getString("type");
if(TypeOfTalking != "")
{
if (TypeOfTalking.contains("readBlock"))
{
if(TypeOfTalking.contains("#"))
{
try
{
String[] parts = TypeOfTalking.split("#");
int index = Integer.parseInt(parts[1]);
Result = Readblock(cordova.getActivity().getIntent(),(byte)index);
callbackContext.success(Result);
}
catch(Exception e)
{
callbackContext.error("Exception Reading "+ TypeOfTalking + "due to "+ e.toString());
return false;
}
}
}
else
{
return false;
}
}
else
{
return false;
}
}
else
{
return false;
}
return true;
}
#Override
public void onNewIntent(Intent intent) {
ShowAlert("onNewIntent called");
Tag tagFromIntent = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
super.onNewIntent(intent);
getActivity().setIntent(intent);
savedTag = tagFromIntent;
savedIntent = intent;
}
#Override
public void onPause(boolean multitasking) {
Log.d(TAG, "onPause " + getActivity().getIntent());
super.onPause(multitasking);
if (multitasking) {
// nfc can't run in background
stopNfc();
}
}
#Override
public void onResume(boolean multitasking) {
Log.d(TAG, "onResume " + getActivity().getIntent());
super.onResume(multitasking);
startNfc();
}
public String Readblock(Intent Intent,byte block) throws IOException{
byte[] response = new byte[]{};
if(Intent != null)
{
Tag myTag = Intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
if(savedTag != null)
myTag = savedTag;
if(myTag != null)
{
try{
Reader nTagReader = new Reader(myTag);
nTagReader.close();
nTagReader.connect();
nTagReader.SectorSelect(Sector.Sector0);
response = nTagReader.fast_read(block, block);
nTagReader.close();
return ConvertH(response);
}catch(Exception e){
ShowAlert(e.toString());
}
}
else
ShowAlert("myTag is null.");
}
return null;
}
private void createPendingIntent() {
if (pendingIntent == null) {
Activity activity = getActivity();
Intent intent = new Intent(activity, activity.getClass());
intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP| Intent.FLAG_ACTIVITY_CLEAR_TOP);
pendingIntent = PendingIntent.getActivity(activity, 0, intent, 0);
}
}
private void startNfc() {
createPendingIntent(); // onResume can call startNfc before execute
getActivity().runOnUiThread(new Runnable() {
public void run() {
NfcAdapter nfcAdapter = NfcAdapter.getDefaultAdapter(getActivity());
if (nfcAdapter != null && !getActivity().isFinishing()) {
try {
nfcAdapter.enableForegroundDispatch(getActivity(), getPendingIntent(), getIntentFilters(), getTechLists());
if (p2pMessage != null) {
nfcAdapter.setNdefPushMessage(p2pMessage, getActivity());
}
} catch (IllegalStateException e) {
// issue 110 - user exits app with home button while nfc is initializing
Log.w(TAG, "Illegal State Exception starting NFC. Assuming application is terminating.");
}
}
}
});
}
private void stopNfc() {
Log.d(TAG, "stopNfc");
getActivity().runOnUiThread(new Runnable() {
public void run() {
NfcAdapter nfcAdapter = NfcAdapter.getDefaultAdapter(getActivity());
if (nfcAdapter != null) {
try {
nfcAdapter.disableForegroundDispatch(getActivity());
} catch (IllegalStateException e) {
// issue 125 - user exits app with back button while nfc
Log.w(TAG, "Illegal State Exception stopping NFC. Assuming application is terminating.");
}
}
}
});
}
private Activity getActivity() {
return this.cordova.getActivity();
}
private PendingIntent getPendingIntent() {
return pendingIntent;
}
private IntentFilter[] getIntentFilters() {
return intentFilters.toArray(new IntentFilter[intentFilters.size()]);
}
private String[][] getTechLists() {
//noinspection ToArrayCallWithZeroLengthArrayArgument
return techLists.toArray(new String[0][0]);
}
}
My index.js file
nfc.addTagDiscoveredListener(
function(nfcEvent){
console.log(nfcEvent.tag.id);
alert(nfcEvent.tag.id);
window.echo("readBlock#88");//call to plugin
},
function() {
alert("Listening for NFC tags.");
},
function() {
alert("NFC activation failed.");
}
);
SE_NfcA.js(plugin interface for interaction b/w index.js and SE_NfcA.java)
window.echo = function(natureOfTalk)
{
alert("Inside JS Interface, arg =" + natureOfTalk);
cordova.exec(function(result){alert("Result is : "+result);},
function(error){alert("Some Error happened : "+ error);},
"SE_NfcA","TalkToNFC",[{"type": natureOfTalk}]);
};
I guess I have messed up with the Intents/Activity Life-Cycle, please help. TIA!
I found a tweak/hack and made it to work.
Before making any call to read or write, I made one dummy Initialize call.
window.echo("Initialize");
window.echo("readBlock#88");//call to plugin to read.
And in the native code of the plugin, on receiving the "Initialize" token I made a startNFC() call.
else if(TypeOfTalking.equalsIgnoreCase("Initialize"))
{
startNfc();
}
I refactoring my threads in order to avoid memory leaks, and I got 2 errors regarding handler and startActivityForResult being called from within the thread ( dealing with GoogleDrive)
I have in my DownloadActivity :
public class DownloadActivity extends Activity {
....
private void getFolderId(){
getFolderIdThread = new GetFolderIdThread();
getFolderIdThread.start();
}
private static class GetFolderIdThread extends Thread {
private Boolean mRunning = false;
#Override
public void run() {
mRunning = true;
fResultList = new ArrayList<File>();
Files f1 = mService.files();
Files.List request = null;
aFolderId = null;
do {
try {
request = f1.list();
String aQuery = "'root' in parents and mimeType='application/vnd.google-apps.folder' and title='"+ aFolderName + "'";
request.setQ(aQuery);
FileList fileList = request.execute();
fResultList.addAll(fileList.getItems());
request.setPageToken(fileList.getNextPageToken());
} catch (UserRecoverableAuthIOException e) {
startActivityForResult(e.getIntent(), REQUEST_AUTHORIZATION); <= THIS RAISES THE ERROR
} catch (IOException e) {
e.printStackTrace();
if (request != null){
request.setPageToken(null);
}
}
} while (request.getPageToken() !=null && request.getPageToken().length() > 0);
if (fResultList.size() == 0) {
Log.d(TAG, "cannot find the training folder at root level");
Message msg = handler.obtainMessage(); <= THIS RAISES THE ERROR
Bundle bundle = new Bundle();
bundle.putInt("msgKey", DownloadActivity.NO_TRAININGS_FOLDER);
msg.setData(bundle);
handler.sendMessage(msg); <= THIS RAISES THE ERROR
} else {
File folder = fResultList.get(0);
aFolderId = folder.getId();
getFolderContents(); <= THIS RAISES THE ERROR
}
}
public void close() {
mRunning = false;
}
}
I have the handler defined in my activity
Handler handler = new Handler() {
#Override
public void handleMessage(Message msg) {
...
}
}
and the onActivityResult
protected void onActivityResult(final int requestCode, final int resultCode, final Intent data) {
switch (requestCode) {
case REQUEST_ACCOUNT_PICKER:
....
break;
}
}
what are my options to bypass this error ?
Your GetFolderIdThread class is static and a static nested class cannot reference non-static methods and fields in the instance of the outer class that created it. Such a nested class can only access static methods and fields in your Activity. Remove static from the class definition and I think your problem will resolve.
You also need to post your call to startActivityForResult on the UI thread. Of course you should be able to use your handler for that, something like:
handler.post(new Runnable()
{
public void run()
{
startActivityForResult(e.getIntent(), REQUEST_AUTHORIZATION);
}
});
Make sure your thread can gracefully complete as well when you do that because it will continue to run.
I need to call the Google activity recognition service through a service (not activity) and run it in the background, of course when the user starts the app, which has an activity (But the service does not called directly from activity).
Therefore I have created a service class (ActivitySensor) and another class (ActivityRecognitionScan).
When I install the app on my Galaxy Nexus S device, the service starts calling onCreate and onDestroy automatically. Even without doing anything in the GUI
It is very strange behaviour. Does anybody has the same experience or solution for it?
I mean I get something as follows in the debug console:
Activity-Logging --- onCreate
Activity-Logging --- onDestroy
Activity-Logging --- onCreate
Activity-Logging --- onDestroy
Activity-Logging --- onCreate
Activity-Logging --- onDestroy
...
Here are my two classes:
public class ActivitySensor extends IntentService {
private ActivityRecognitionScan myascan;
private Intent inIntent;
private static long ACTIVITY_LOG_INTERVAL = 30000L;
private static JsonEncodeDecode jsonencoder = new JsonEncodeDecode();
public ActivitySensor() {
super("ActivitySensor");
}
#Override
public void onCreate(){
super.onCreate();
Log.d("Activity-Logging", "--- onCreate");
try {
myascan = new ActivityRecognitionScan(getApplicationContext());
myascan.startActivityRecognitionScan();
} catch (Exception e) {
Log.e("[Activity-Logging]","----------Error:"+e.getLocalizedMessage());
e.printStackTrace();
}
}
#Override
public void readSensor() {
// Log.e("Activity-Logging", "ActivityRecognitionResult.hasResult: "+String.valueOf(ActivityRecognitionResult.hasResult(inIntent)));
if (ActivityRecognitionResult.hasResult(inIntent)) {
ActivityRecognitionResult result = ActivityRecognitionResult.extractResult(inIntent);
DetectedActivity activity = result.getMostProbableActivity();
final int type = activity.getType();
String strType = new String();
switch(type){
case DetectedActivity.IN_VEHICLE:
strType = "invehicle";
break;
case DetectedActivity.ON_BICYCLE:
strType ="onbicycle";
break;
case DetectedActivity.ON_FOOT:
strType = "onfoot";
break;
case DetectedActivity.STILL:
strType = "still";
break;
case DetectedActivity.TILTING:
strType ="tilting";
break;
case DetectedActivity.UNKNOWN:
strType ="unknown";
break;
}
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
Editor edt = prefs.edit();
String previousActv = prefs.getString("PREVIOUS_ACTIVIY","");
long previousDate = prefs.getLong("PREVIOUS_DATE", 0);
if (previousActv.length()==0){ // nothing was in the string and it is the first time just initialize
previousActv = strType;
previousDate = new Date().getTime();
// Log.e("-----FIRST TIME: type:", previousActv+" date:"+String.valueOf(previousDate));
edt.putString("PREVIOUS_ACTIVIY", strType);
edt.putLong("PREVIOUS_DATE", previousDate);
edt.commit();
}else {
if (!strType.equalsIgnoreCase(previousActv)){
Date readablePrevDate = new Date(previousDate);
Date nowDate = new Date();
String jsonstr = jsonencoder.EncodeActivity("Activity", readablePrevDate, nowDate, strType, activity.getConfidence());
// Log.e("[Activity-Logging] ----->",jsonstr);
edt.putString("PREVIOUS_ACTIVIY", strType);
edt.putLong("PREVIOUS_DATE", nowDate.getTime());
edt.commit();
DataAcquisitor.dataBuff.add(jsonstr);
}
}
}
}
#Override
protected void onHandleIntent(Intent intent) {
Log.d("Activity-Logging", "--- onHandleIntent"+ "---"+intent.getAction());
intent.putExtra("LOG_INTERVAL",ACTIVITY_LOG_INTERVAL );
intent.putExtra("STOP",false);
inIntent = intent;
readSensor();
}
#Override
public void onDestroy(){
Log.d("Activity-Logging", "--- onDestroy");
myascan.stopActivityRecognitionScan();
myascan=null;
//super.onDestroy();
}
}
This is the class that calls the Google Activity Recognition Service:
ActivityRecognitionScan implements GooglePlayServicesClient.ConnectionCallbacks, GooglePlayServicesClient.OnConnectionFailedListener {
private Context ctx;
private static final String TAG = "ActivityRecognition";
private static ActivityRecognitionClient actrecClient;
private static PendingIntent callbackIntent;
private long ACTIVITY_LOG_INTERVAL=30000;
public ActivityRecognitionScan(Context context) {
ctx=context;
}
public void startActivityRecognitionScan(){
int resp = GooglePlayServicesUtil.isGooglePlayServicesAvailable(ctx);
if(resp == ConnectionResult.SUCCESS){
actrecClient = new ActivityRecognitionClient(ctx, this, this);
if (!actrecClient.isConnected()){
actrecClient.connect();
} else{
Log.e("ActivityRecognitionScan"," ---Activity recognition client is already connected");
}
}else{
Log.e("[Activity-Logging]", "Google Play Service hasn't installed");
}
}
public void stopActivityRecognitionScan(){
try{
if (actrecClient.isConnected() || actrecClient.isConnecting() ){
actrecClient.removeActivityUpdates(callbackIntent);
actrecClient.disconnect();
}
} catch (Exception e){
e.printStackTrace();
}
}
#Override
public void onConnectionFailed(ConnectionResult result) {
Log.e("[ActivityRecognitionScan]", "Connection Failed");
}
#Override
public void onConnected(Bundle connectionHint) {
try{
Intent intent = new Intent(ctx, ActivitySensor.class);
Bundle bundle = intent.getExtras();
callbackIntent = PendingIntent.getService(ctx, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
long interval = 5000;
if ( null!= bundle && bundle.containsKey("LOG_INTERVAL") ){
interval = bundle.getLong("LOG_INTERVAL");
}
actrecClient.requestActivityUpdates(interval, callbackIntent);
actrecClient.disconnect();
}catch(Exception ex){
Log.e("[Activity-Logging]","Error in requesting Activity update "+ex.getMessage());
ex.printStackTrace();
}
}
#Override
public void onDisconnected() {
callbackIntent.cancel();
actrecClient = null;
Log.e("[ActivityRecognitionScan]","---onDisconnected");
}
}
IntentService automatically stops itself on completion of onHandleIntent as per the source code (see ServiceHandler.handleMessage()) as per the description of an IntentService:
Clients send requests through startService(Intent) calls; the service is started as needed, handles each Intent in turn using a worker thread, and stops itself when it runs out of work.
Use a Service if you want it to run continuously in the background.
You have 2 issues with your code that is causing the problem you are experiencing.
When activity is detected, the pending intent that is called calls (and creates, since it is an IntentService) ActivitySensor. The onCreate will connect another ActivityRecognitionClient, which is unnecessary. This causes another activity to be detected which causes your logging loop.
You should separate the creation of the ActivityRecognitionClient from the handling of the detected activity. You don't need to keep recreating it as subsequent detections will use the same PendingIntent. This will prevent the logging loop.
I want to block a specific phone number that is in my database
I do a comparison between the number the user dialed, and the number in memory. If they are equal, I block the call.
My code:
public void onReceive(Context context, Intent intent) {
PlaceDataSQL placeDataSQL =new PlaceDataSQL(context);
ArrayList<String> getUsersPhoneNumbers= placeDataSQL.getUsersPhoneNumbers();
//TODO
//===========
//here I need to check the number
Bundle b = intent.getExtras();
String incommingNumber = b.getString(TelephonyManager.EXTRA_INCOMING_NUMBER);
//String outGoingNumber = b.getString(TelephonyManager.);
Boolean find=false;
try {
for(int i=0;i<getUsersPhoneNumbers.size();i++)
{
if(incommingNumber.equals(getUsersPhoneNumbers.get(i)))
{
find=true;
break;
}
}
} catch (Exception e) {
incommingNumber="";
}
// ========================================
//here the problem
//=========================================
String phonenumber=b.getString(Intent.EXTRA_PHONE_NUMBER);
try {
for(int i=0;i<getUsersPhoneNumbers.size();i++)
{
if(phonenumber.equals(getUsersPhoneNumbers.get(i)))
{
find=true;
break;
}
}
if (!find)
return;
}catch (Exception e) {
phonenumber="";
}
if (!find)
return;
/* examine the state of the phone that caused this receiver to fire off */
String phone_state = intent.getStringExtra(TelephonyManager.EXTRA_STATE);
if (phone_state.equals(TelephonyManager.EXTRA_STATE_RINGING))
{
logMe("Phone Ringing: the phone is ringing, scheduling creation call answer screen activity");
Intent i = new Intent(context, CallAnswerIntentService.class);
i.putExtra("delay", 100L);
i.putExtra("number", incommingNumber);
context.startService(i);
logMe("Phone Ringing: started, time to go back to listening");
}
if (phone_state.equals(TelephonyManager.EXTRA_STATE_OFFHOOK))
{
Intent i = new Intent(context,InCallScreenGuardService.class);
i.putExtra("delay", 100L);
i.putExtra("number", phonenumber);
logMe("Phone Offhook: starting screen guard service");
context.startService(i);
}
if (phone_state.equals(TelephonyManager.EXTRA_STATE_IDLE))
{
Intent i = new Intent(context,InCallScreenGuardService.class);
logMe("Phone Idle: stopping screen guard service");
context.stopService(i);
}
return;
}
The problem:
I can get incoming numbers but I can't get outgoing numbers?
You will need a BroadcastReciever for this.
public class OutgoingCallReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
Bundle bundle = intent.getExtras();
if(null == bundle)
return;
String phonenumber = intent.getStringExtra(Intent.EXTRA_PHONE_NUMBER);
Log.i("OutgoingCallReceiver",phonenumber);
Log.i("OutgoingCallReceiver",bundle.toString());
String info = "Detect Calls sample application\nOutgoing number: " + phonenumber;
Toast.makeText(context, info, Toast.LENGTH_LONG).show();
}
}