Related
I've been for some days now having this error of trying to insert an object, check that it has actually been inserted, then retrieve that object id to create the record in the many-to-many table, but for some reason, I always get the 787 error saying that I'm basically creating this record without existing in the parent table in the first place, which is impossible since, well, I check it just as I create it, and it is there. How can I fix this?
This is the activity where I insert both records (bottom part):
package com.gmproxy.pastilarma;
import androidx.appcompat.app.AppCompatActivity;
import androidx.lifecycle.ViewModelProvider;
import android.app.TimePickerDialog;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.TimePicker;
import android.widget.Toast;
import com.gmproxy.DAO.AlarmRepository;
import com.gmproxy.DAO.AlarmUserRepository;
import com.gmproxy.Entities.Alarm;
import com.gmproxy.Entities.Medicine;
import com.gmproxy.Entities.User;
import com.gmproxy.Alarm.UtilAlarma;
import com.gmproxy.ViewModels.AlarmViewModel;
import com.gmproxy.ViewModels.MedicineViewModel;
import com.gmproxy.ViewModels.UserViewModel;
import java.util.Calendar;
public class UserAlarmScreen extends AppCompatActivity {
TextView usernameAlarm,numHabText,medicineText,notificationsTime;
EditText medicineQuantityText;
Button gotoBackBtn,gotoMedicinesBtn,confirmAlarmBtn;
int alarmID = 1;
int idM,idU;
SharedPreferences settings;
User user;
Medicine medicine;
Alarm alarm;
AlarmUserRepository alUsRe;
AlarmRepository alRe;
AlarmViewModel alarmViewModel;
UserViewModel userViewModel;
MedicineViewModel medicineViewModel;
String medicineQuantity;
int med_record;
Calendar today;
String message;
Context context;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_user_alarm_screen);
context = this.getApplicationContext();
idU = getIntent().getIntExtra("id_userA",0);
Log.println(Log.INFO,"id",String.valueOf(idU));
idM = getIntent().getIntExtra("med",0);
Log.println(Log.INFO,"Id medicina",String.valueOf(idM));
med_record = getIntent().getIntExtra("med-record",0);
/*
If we come back from medicine search, we actually reload everything that was writter before, so that the user doesn't have to rewrite it
*/
if (med_record == 1){
loadPreferences();
}
userViewModel = new ViewModelProvider(this, new ViewModelProvider.AndroidViewModelFactory(getApplication())).get(UserViewModel.class);
alarmViewModel = new ViewModelProvider(this, new ViewModelProvider.AndroidViewModelFactory(getApplication())).get(AlarmViewModel.class);
medicineViewModel = new ViewModelProvider(this, new ViewModelProvider.AndroidViewModelFactory(getApplication())).get(MedicineViewModel.class);
alUsRe = new AlarmUserRepository(this.getApplication());
alRe = new AlarmRepository(this.getApplication());
user = userViewModel.getObjectById(idU);
medicine = medicineViewModel.getMedicineById(idM);
usernameAlarm = findViewById(R.id.UsernameAlarm);
usernameAlarm.setText(user.getUser_name() + " " + user.getUser_surname());
numHabText = findViewById(R.id.NumHabText);
numHabText.setText(String.valueOf(user.getRoom_number()));
medicineText = findViewById(R.id.MedicineText);
if (idM > 0){
medicineText.setText(medicine.getMedicineName());
}
medicineQuantityText = findViewById(R.id.MedicineQuantity);
medicineQuantity = medicineQuantityText.getText().toString();
gotoBackBtn = findViewById(R.id.gotoBack);
notificationsTime = findViewById(R.id.HoraInput);
gotoMedicinesBtn = findViewById(R.id.gotoMedicines);
confirmAlarmBtn = findViewById(R.id.ConfirmAlarm);
/*
Now this is pod racing. From here on out until the create method ends, we'll be creating the actual alarm+notification!
Isn't it exciting!?
No it's not, please do keep reading.
*/
settings = getSharedPreferences(getString(R.string.app_name), Context.MODE_PRIVATE);
String hour, minute;
hour = settings.getString("hour","");
minute = settings.getString("minute","");
if(hour.length() > 0)
{
notificationsTime.setText(hour + ":" + minute);
}
/*
This displays the TimePicker and automatically writes it down for the notification to be created
*/
findViewById(R.id.CambiarNotificacion).setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Calendar mcurrentTime = Calendar.getInstance();
int hour = mcurrentTime.get(Calendar.HOUR_OF_DAY);
int minute = mcurrentTime.get(Calendar.MINUTE);
TimePickerDialog mTimePicker;
mTimePicker = new TimePickerDialog(UserAlarmScreen.this, new TimePickerDialog.OnTimeSetListener() {
#Override
public void onTimeSet(TimePicker timePicker, int selectedHour, int selectedMinute) {
String finalHour, finalMinute;
finalHour = "" + selectedHour;
finalMinute = "" + selectedMinute;
if (selectedHour < 10) finalHour = "0" + selectedHour;
if (selectedMinute < 10) finalMinute = "0" + selectedMinute;
notificationsTime.setText(finalHour + ":" + finalMinute);
today = Calendar.getInstance();
today.set(Calendar.HOUR_OF_DAY, selectedHour);
today.set(Calendar.MINUTE, selectedMinute);
today.set(Calendar.SECOND, 0);
SharedPreferences.Editor edit = settings.edit();
edit.putString("hour", finalHour);
edit.putString("minute", finalMinute);
//SAVE ALARM TIME TO USE IT IN CASE OF REBOOT
edit.putInt("alarmID", alarmID);
edit.putLong("alarmTime", today.getTimeInMillis());
edit.commit();
Toast.makeText(UserAlarmScreen.this, "Alarma puesta a las " + finalHour + ":" + finalMinute, Toast.LENGTH_LONG).show();
}
}, hour, minute, true);//Yes 24 hour time
mTimePicker.setTitle("Escoge una hora");
mTimePicker.show();
}
});
}
private void loadPreferences(){
SharedPreferences preferences = getSharedPreferences("dataA",Context.MODE_PRIVATE);
idU = preferences.getInt("idU",0);
}
private void savePreferences(){
SharedPreferences preferences = getSharedPreferences("dataA",Context.MODE_PRIVATE);
SharedPreferences.Editor editer = preferences.edit();
editer.putInt("idU",idU);
editer.commit();
}
public void gotoBack(View view){
Intent mainAct = new Intent(UserAlarmScreen.this, UserInfoScreen.class);
mainAct.putExtra("id_user",idU);
startActivity(mainAct);
}
public void gotoMedicines(View view){
Intent mainAct = new Intent(UserAlarmScreen.this, PillsSearchScreen.class);
mainAct.putExtra("id_userB",idU);
savePreferences();
startActivity(mainAct);
}
/**
* Pretty much self explanatory, confirms the alarm and adds it to the database, both to the alarm table and
* the alarm-user table in order to be shown in the recycler view back at user-info-screen.
* #param view
*/
public void confirmAlarm(View view) throws InterruptedException {
alRe.insertAlarm(medicine.getId_medicine(),
notificationsTime.getText().toString());
Log.println(Log.INFO,"Med check null",String.valueOf(medicine.getId_medicine()));
Log.println(Log.INFO,"Hour check null",notificationsTime.getText().toString());
int idAl = alarmViewModel.getAlarmbyTimeAndMedId(notificationsTime.getText().toString(),medicine.getId_medicine());
Log.println(Log.INFO,"Alarm Id Res check null",String.valueOf(alRe.getAlarmbyTimeAndMedId(notificationsTime.getText().toString(),medicine.getId_medicine())));
Log.println(Log.INFO,"Alarm Id check null",String.valueOf(idAl));
alUsRe.insertObjectById(idAl,idU);
message = "El paciente " + user.getUser_name() + " " + user.getUser_surname()
+ " tiene apuntada la medicación " + medicine.getMedicineName() + " a las " + notificationsTime.getText().toString() + " horas.";
UtilAlarma.setAlarm(idAl, today.getTimeInMillis(), UserAlarmScreen.this, message);
Intent mainAct = new Intent(UserAlarmScreen.this, UserInfoScreen.class);
int id = 1;
mainAct.putExtra("alar-record",id);
startActivity(mainAct);
}
}
And this is the stack trace:
I/Med check null: 12684
I/Hour check null: 01:28
I/Alarm Id Res check null: 26
I/Alarm Id check null: 0
E/AndroidRuntime: FATAL EXCEPTION: pool-3-thread-2
Process: com.gmproxy.pastilarma, PID: 6015
android.database.sqlite.SQLiteConstraintException: FOREIGN KEY constraint failed (code 787 SQLITE_CONSTRAINT_FOREIGNKEY)
at android.database.sqlite.SQLiteConnection.nativeExecuteForLastInsertedRowId(Native Method)
at android.database.sqlite.SQLiteConnection.executeForLastInsertedRowId(SQLiteConnection.java:938)
at android.database.sqlite.SQLiteSession.executeForLastInsertedRowId(SQLiteSession.java:790)
at android.database.sqlite.SQLiteStatement.executeInsert(SQLiteStatement.java:88)
at androidx.sqlite.db.framework.FrameworkSQLiteStatement.executeInsert(FrameworkSQLiteStatement.java:51)
at com.gmproxy.DAO.AlarmUserDAO_Impl.insertIntoAlarmUser(AlarmUserDAO_Impl.java:150)
at com.gmproxy.DAO.AlarmUserRepository.lambda$insertObjectById$1$AlarmUserRepository(AlarmUserRepository.java:41)
at com.gmproxy.DAO.-$$Lambda$AlarmUserRepository$2T5LlZH-RbFoUm3l2obKvPWaNZU.run(Unknown Source:6)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
at java.lang.Thread.run(Thread.java:923)
So, it all went down to making sure that the object in java was first created, then inserted. I was getting that error becuase it was being inserted wrongly with id=0, therefore returning error 787.
Am new for android . I want send sms after click send button
first i have used sms manager api.
package com.example.smsproject;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.telephony.SmsManager;
import android.view.View;`enter code here`
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;
public class Page2Activity extends Activity {
Button button;
EditText textPhoneNo;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
button = (Button) findViewById(R.id.button1);
textPhoneNo = (EditText) findViewById(R.id.mobilenumber);
button.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v){
//String phoneNo = textPhoneNo.getText().toString();
String phoneNo = "tel:xxxxxxxxxx";
String messageText = "SMS FROM ANDROID";
try {
SmsManager smsManager = SmsManager.getDefault();
smsManager.sendTextMessage(phoneNo, null, messageText, null, null);
Toast.makeText(getApplicationContext(), "SMS Sent Successfully!",
Toast.LENGTH_LONG).show();
}catch (Exception e){
Toast.makeText(getApplicationContext(),
"SMS failed, please try again later ! ",
Toast.LENGTH_LONG).show();
e.printStackTrace();
}
}
});
}
}
set send_sms permission on android_manifest.xml
i got zero errors but sms not sending. If you have know answer.
please let me know, thanks for reading.
To complete #Android Fanatic answer
If the text is too long, the message does not go away, you have to respect max length depending of encoding.
More information can be found here.
I'd prefer this method
SmsManager sms = SmsManager.getDefault();
ArrayList<String> parts = sms.divideMessage(message);
ArrayList<PendingIntent> sendList = new ArrayList<>();
sendList.add(sentPI);
ArrayList<PendingIntent> deliverList = new ArrayList<>();
deliverList.add(deliveredPI);
sms.sendMultipartTextMessage(phoneNumber, null, parts, sendList, deliverList);
Also SMS Manager doesn't sent messages if the message is longer than 160 for English text, and 70 for 16-bit alphabet text. Try sending small English text to see if it's the case.
(You can sent multiple part messages to send long texts).
String incomming = "9876543210";
android.telephony.SmsManager sms=android.telephony.SmsManager.getDefault();
sms.sendTextMessage(incomming, null,"Here Is Sms", null, null);
Log.d("SMS ready to send", "----FIRST CALL----");
String number = "111111111111"; //ed1.getText().toString();
String message = "Test SMS DATA"; //ed2.getText().toString();
Log.d("SMS ready to send", "----SECOND CALL----"+number);
SmsManager sms = SmsManager.getDefault();
sms.sendTextMessage(number, null, message, null, null);
Log.d("SMS ready to send", "----THIRD CALL----");
I'm making an attendance system in android where employee should be able to put attendance only if he is in office premises through his mobile fingerprint scanner and I want to retrieve data like employee_name, location, date, time and save it in php I coded for geofencing but don't know how to proceed further below is code for geofencing
I searched all over the internet but didn't find a proper solution please anyone help me I really need this.....
MyGeoFenCIN.java
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.support.annotation.NonNull;
import android.util.Log;
import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.common.api.Result;
import com.google.android.gms.common.api.ResultCallback;
import com.google.android.gms.location.Geofence;
import com.google.android.gms.location.GeofencingRequest;
import com.google.android.gms.location.LocationServices;
import com.google.android.gms.location.places.Place;
import com.google.android.gms.location.places.PlaceBuffer;
import java.util.ArrayList;
import java.util.List;
public class Geofencing implements ResultCallback {
// Constants
public static final String TAG = Geofencing.class.getSimpleName();
private static final float GEOFENCE_RADIUS = 1606; // 50 meters
private static final long GEOFENCE_TIMEOUT = 24 * 60 * 60 * 1000; // 24 hours
private List<Geofence> mGeofenceList;
private PendingIntent mGeofencePendingIntent;
private GoogleApiClient mGoogleApiClient;
private Context mContext;
public Geofencing(Context context, GoogleApiClient client) {
mContext = context;
mGoogleApiClient = client;
mGeofencePendingIntent = null;
mGeofenceList = new ArrayList<>();
}
/***
* Registers the list of Geofences specified in mGeofenceList with Google Place Services
* Uses {#code #mGoogleApiClient} to connect to Google Place Services
* Uses {#link #getGeofencingRequest} to get the list of Geofences to be registered
* Uses {#link #getGeofencePendingIntent} to get the pending intent to launch the IntentService
* when the Geofence is triggered
* Triggers {#link #onResult} when the geofences have been registered successfully
*/
public void registerAllGeofences() {
// Check that the API client is connected and that the list has Geofences in it
if (mGoogleApiClient == null || !mGoogleApiClient.isConnected() ||
mGeofenceList == null || mGeofenceList.size() == 0) {
return;
}
try {
LocationServices.GeofencingApi.addGeofences(
mGoogleApiClient,
getGeofencingRequest(),
getGeofencePendingIntent()
).setResultCallback(this);
} catch (SecurityException securityException) {
// Catch exception generated if the app does not use ACCESS_FINE_LOCATION permission.
Log.e(TAG, securityException.getMessage());
}
}
/***
* Unregisters all the Geofences created by this app from Google Place Services
* Uses {#code #mGoogleApiClient} to connect to Google Place Services
* Uses {#link #getGeofencePendingIntent} to get the pending intent passed when
* registering the Geofences in the first place
* Triggers {#link #onResult} when the geofences have been unregistered successfully
*/
public void unRegisterAllGeofences() {
if (mGoogleApiClient == null || !mGoogleApiClient.isConnected()) {
return;
}
try {
LocationServices.GeofencingApi.removeGeofences(
mGoogleApiClient,
// This is the same pending intent that was used in registerGeofences
getGeofencePendingIntent()
).setResultCallback(this);
} catch (SecurityException securityException) {
// Catch exception generated if the app does not use ACCESS_FINE_LOCATION permission.
Log.e(TAG, securityException.getMessage());
}
}
/***
* Updates the local ArrayList of Geofences using data from the passed in list
* Uses the Place ID defined by the API as the Geofence object Id
*
* #param places the PlaceBuffer result of the getPlaceById call
*/
public void updateGeofencesList(PlaceBuffer places) {
mGeofenceList = new ArrayList<>();
if (places == null || places.getCount() == 0) return;
for (Place place : places) {
// Read the place information from the DB cursor
String placeUID = place.getId();
double placeLat = place.getLatLng().latitude;
double placeLng = place.getLatLng().longitude;
// Build a Geofence object
Geofence geofence = new Geofence.Builder()
.setRequestId(placeUID)
.setExpirationDuration(GEOFENCE_TIMEOUT)
.setCircularRegion(placeLat, placeLng, GEOFENCE_RADIUS)
.setTransitionTypes(Geofence.GEOFENCE_TRANSITION_ENTER | Geofence.GEOFENCE_TRANSITION_EXIT)
.build();
// Add it to the list
mGeofenceList.add(geofence);
}
}
/***
* Creates a GeofencingRequest object using the mGeofenceList ArrayList of Geofences
* Used by {#code #registerGeofences}
*
* #return the GeofencingRequest object
*/
private GeofencingRequest getGeofencingRequest() {
GeofencingRequest.Builder builder = new GeofencingRequest.Builder();
builder.setInitialTrigger(GeofencingRequest.INITIAL_TRIGGER_ENTER);
builder.addGeofences(mGeofenceList);
return builder.build();
}
/***
* Creates a PendingIntent object using the GeofenceTransitionsIntentService class
* Used by {#code #registerGeofences}
*
* #return the PendingIntent object
*/
private PendingIntent getGeofencePendingIntent() {
// Reuse the PendingIntent if we already have it.
if (mGeofencePendingIntent != null) {
return mGeofencePendingIntent;
}
Intent intent = new Intent(mContext, GeofenceTransitionsIntentService.class);
mGeofencePendingIntent = PendingIntent.getService(mContext, 0, intent, PendingIntent.
FLAG_UPDATE_CURRENT);
return mGeofencePendingIntent;
}
#Override
public void onResult(#NonNull Result result) {
Log.e(TAG, String.format("Error adding/removing geofence : %s",
result.getStatus().toString()));
}
}
GeofenceTransitionsIntentService.java
import android.app.AlarmManager;
import android.app.IntentService;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.graphics.BitmapFactory;
import android.graphics.Color;
import android.net.Uri;
import android.preference.PreferenceManager;
import android.support.annotation.NonNull;
import android.support.v4.app.NotificationCompat;
import android.support.v4.app.TaskStackBuilder;
import android.text.TextUtils;
import android.util.Log;
import android.widget.Toast;
import com.google.android.gms.common.api.PendingResult;
import com.google.android.gms.common.api.ResultCallback;
import com.google.android.gms.location.Geofence;
import com.google.android.gms.location.GeofencingEvent;
import com.google.android.gms.location.places.GeoDataClient;
import com.google.android.gms.location.places.Place;
import com.google.android.gms.location.places.PlaceBuffer;
import com.google.android.gms.location.places.PlaceBufferResponse;
import com.google.android.gms.location.places.Places;
import com.google.android.gms.tasks.OnCompleteListener;
import com.google.android.gms.tasks.Task;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;
import java.util.Map;
/**
* Listener for geofence transition changes.
*
* Receives geofence transition events from Location Services in the form of an Intent containing
* the transition type and geofence id(s) that triggered the transition. Creates a notification
* as the output.
*/
public class GeofenceTransitionsIntentService extends IntentService {
private static final String TAG = "GeofenceTransitionsIS";
private GeoDataClient mGeoDataClient;
String geofenceTransitionString;
/**
* This constructor is required, and calls the super IntentService(String)
* constructor with the name for a worker thread.
*/
public GeofenceTransitionsIntentService() {
// Use the TAG to name the worker thread.
super(TAG);
}
/**
* Handles incoming intents.
* #param intent sent by Location Services. This Intent is provided to Location
* Services (inside a PendingIntent) when addGeofences() is called.
*/
#Override
protected void onHandleIntent(Intent intent) {
GeofencingEvent geofencingEvent = GeofencingEvent.fromIntent(intent);
if (geofencingEvent.hasError()) {
//String errorMessage = GeofenceErrorMessages.getErrorString(this,
// geofencingEvent.getErrorCode());
//Log.e(TAG, errorMessage);
return;
}
// Get the transition type.
int geofenceTransition = geofencingEvent.getGeofenceTransition();
// Test that the reported transition was of interest.
if (geofenceTransition == Geofence.GEOFENCE_TRANSITION_ENTER ||
geofenceTransition == Geofence.GEOFENCE_TRANSITION_EXIT) {
// Get the geofences that were triggered. A single event can trigger multiple geofences.
List<Geofence> triggeringGeofences = geofencingEvent.getTriggeringGeofences();
// Get the transition details as a String.
String geofenceTransitionDetails = getGeofenceTransitionDetails(geofenceTransition,
triggeringGeofences);
mGeoDataClient = Places.getGeoDataClient(this, null);
mGeoDataClient.getPlaceById(geofenceTransitionDetails).addOnCompleteListener(new OnCompleteListener<PlaceBufferResponse>() {
#Override
public void onComplete(#NonNull Task<PlaceBufferResponse> task) {
if (task.isSuccessful()) {
PlaceBufferResponse places = task.getResult();
Place myPlace = places.get(0);
Log.i(TAG, "Place found: " + myPlace.getName());
CharSequence name = myPlace.getName();
String placeName = name.toString();
places.release();
Calendar currentTime = Calendar.getInstance();
SimpleDateFormat df = new SimpleDateFormat("dd-MMM-yyyy HH:mm:ss");
String formattedDate = df.format(currentTime.getTime());
sendNotification(geofenceTransitionString + ": " + placeName + " " + formattedDate);
} else {
Log.e(TAG, "Place not found.");
}
}
});
Log.i(TAG, geofenceTransitionDetails);
} else {
// Log the error.
Log.e(TAG, getString(R.string.geofence_transition_invalid_type,
geofenceTransition));
}
}
/**
* Gets transition details and returns them as a formatted string.
*
* #param geofenceTransition The ID of the geofence transition.
* #param triggeringGeofences The geofence(s) triggered.
* #return The transition details formatted as String.
*/
private String getGeofenceTransitionDetails(
int geofenceTransition,
List<Geofence> triggeringGeofences) {
geofenceTransitionString = getTransitionString(geofenceTransition);
// Get the Ids of each geofence that was triggered.
ArrayList<String> triggeringGeofencesIdsList = new ArrayList<>();
for (Geofence geofence : triggeringGeofences) {
triggeringGeofencesIdsList.add(geofence.getRequestId());
}
String triggeringGeofencesIdsString = TextUtils.join(", ", triggeringGeofencesIdsList);
return triggeringGeofencesIdsString;
}
/**
* Posts a notification in the notification bar when a transition is detected.
* If the user clicks the notification, control goes to the MainActivity.
*/
private void sendNotification(String notificationDetails) {
// Create an explicit content Intent that starts the main Activity.
Intent notificationIntent = new Intent(getApplicationContext(), MainActivity.class);
// Construct a task stack.
TaskStackBuilder stackBuilder = TaskStackBuilder.create(this);
// Add the main Activity to the task stack as the parent.
stackBuilder.addParentStack(MainActivity.class);
// Push the content Intent onto the stack.
stackBuilder.addNextIntent(notificationIntent);
// Get a PendingIntent containing the entire back stack.
PendingIntent notificationPendingIntent =
stackBuilder.getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT);
// Get a notification builder that's compatible with platform versions >= 4
NotificationCompat.Builder builder = new NotificationCompat.Builder(this);
// Define the notification settings.
builder.setSmallIcon(R.mipmap.ic_launcher)
// In a real app, you may want to use a library like Volley
// to decode the Bitmap.
.setLargeIcon(BitmapFactory.decodeResource(getResources(),
R.mipmap.ic_launcher))
.setColor(Color.RED)
.setContentTitle(notificationDetails)
.setContentText(getString(R.string.geofence_transition_notification_text))
.setContentIntent(notificationPendingIntent);
// Dismiss notification once the user touches it.
builder.setAutoCancel(true);
// Get an instance of the Notification manager
NotificationManager mNotificationManager =
(NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
// Issue the notification
mNotificationManager.notify(0, builder.build());
}
/**
* Maps geofence transition types to their human-readable equivalents.
*
* #param transitionType A transition type constant defined in Geofence
* #return A String indicating the type of transition
*/
private String getTransitionString(int transitionType) {
switch (transitionType) {
case Geofence.GEOFENCE_TRANSITION_ENTER:
return getString(R.string.geofence_transition_entered);
case Geofence.GEOFENCE_TRANSITION_EXIT:
return getString(R.string.geofence_transition_exited);
default:
return getString(R.string.unknown_geofence_transition);
}
}
}
So here I don't know how to make a condition that employee can put attendance only if he is in office premises and after attendance storing data in php I have seen apps on play store doing the same but I don't know how to do this
MyPlaceAdapter.java
import android.content.Context;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import com.locationgeo.R;
import com.google.android.gms.location.places.PlaceBuffer;
public class PlaceListAdapter extends RecyclerView.Adapter<PlaceListAdapter.PlaceViewHolder> {
private Context mContext;
private PlaceBuffer mPlaces;
public PlaceListAdapter(Context context, PlaceBuffer places) {
this.mContext = context;
this.mPlaces = places;
}
#Override
public PlaceViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
// Get the RecyclerView item layout
LayoutInflater inflater = LayoutInflater.from(mContext);
View view = inflater.inflate(R.layout.item_place_card, parent, false);
return new PlaceViewHolder(view);
}
#Override
public void onBindViewHolder(PlaceViewHolder holder, int position) {
String placeName = mPlaces.get(position).getName().toString();
String placeAddress = mPlaces.get(position).getAddress().toString();
holder.nameTextView.setText(placeName);
holder.addressTextView.setText(placeAddress);
}
public void swapPlaces(PlaceBuffer newPlaces){
mPlaces = newPlaces;
if (mPlaces != null) {
// Force the RecyclerView to refresh
this.notifyDataSetChanged();
}
}
#Override
public int getItemCount() {
if(mPlaces==null) return 0;
return mPlaces.getCount();
}
/**
* PlaceViewHolder class for the recycler view item
*/
class PlaceViewHolder extends RecyclerView.ViewHolder {
TextView nameTextView;
TextView addressTextView;
public PlaceViewHolder(View itemView) {
super(itemView);
nameTextView = (TextView) itemView.findViewById(R.id.name_text_view);
addressTextView = (TextView) itemView.findViewById(R.id.address_text_view);
}
}
}
PlaceProvider.java
import android.content.ContentProvider;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.Context;
import android.content.UriMatcher;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.net.Uri;
import android.support.annotation.NonNull;
public class PlaceContentProvider extends ContentProvider {
public static final int PLACES = 100;
public static final int PLACE_WITH_ID = 101;
// Declare a static variable for the Uri matcher that you construct
private static final UriMatcher sUriMatcher = buildUriMatcher();
private static final String TAG = PlaceContentProvider.class.getName();
// Define a static buildUriMatcher method that associates URI's with their int match
public static UriMatcher buildUriMatcher() {
// Initialize a UriMatcher
UriMatcher uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
// Add URI matches
uriMatcher.addURI(PlaceContract.AUTHORITY, PlaceContract.PATH_PLACES, PLACES);
uriMatcher.addURI(PlaceContract.AUTHORITY, PlaceContract.PATH_PLACES + "/#", PLACE_WITH_ID);
return uriMatcher;
}
// Member variable for a PlaceDbHelper that's initialized in the onCreate() method
private PlaceDbHelper mPlaceDbHelper;
#Override
public boolean onCreate() {
Context context = getContext();
mPlaceDbHelper = new PlaceDbHelper(context);
return true;
}
/***
* Handles requests to insert a single new row of data
*
* #param uri
* #param values
* #return
*/
#Override
public Uri insert(#NonNull Uri uri, ContentValues values) {
final SQLiteDatabase db = mPlaceDbHelper.getWritableDatabase();
// Write URI matching code to identify the match for the places directory
int match = sUriMatcher.match(uri);
Uri returnUri; // URI to be returned
switch (match) {
case PLACES:
// Insert new values into the database
long id = db.insert(PlaceContract.PlaceEntry.TABLE_NAME, null, values);
if (id > 0) {
returnUri = ContentUris.withAppendedId(PlaceContract.PlaceEntry.CONTENT_URI, id);
} else {
throw new android.database.SQLException("Failed to insert row into " + uri);
}
break;
// Default case throws an UnsupportedOperationException
default:
throw new UnsupportedOperationException("Unknown uri: " + uri);
}
// Notify the resolver if the uri has been changed, and return the newly inserted URI
getContext().getContentResolver().notifyChange(uri, null);
// Return constructed uri (this points to the newly inserted row of data)
return returnUri;
}
#Override
public Cursor query(#NonNull Uri uri, String[] projection, String selection,
String[] selectionArgs, String sortOrder) {
// Get access to underlying database (read-only for query)
final SQLiteDatabase db = mPlaceDbHelper.getReadableDatabase();
// Write URI match code and set a variable to return a Cursor
int match = sUriMatcher.match(uri);
Cursor retCursor;
switch (match) {
// Query for the places directory
case PLACES:
retCursor = db.query(PlaceContract.PlaceEntry.TABLE_NAME,
projection,
selection,
selectionArgs,
null,
null,
sortOrder);
break;
// Default exception
default:
throw new UnsupportedOperationException("Unknown uri: " + uri);
}
// Set a notification URI on the Cursor and return that Cursor
retCursor.setNotificationUri(getContext().getContentResolver(), uri);
// Return the desired Cursor
return retCursor;
}
#Override
public int delete(#NonNull Uri uri, String selection, String[] selectionArgs) {
// Get access to the database and write URI matching code to recognize a single item
final SQLiteDatabase db = mPlaceDbHelper.getWritableDatabase();
int match = sUriMatcher.match(uri);
// Keep track of the number of deleted places
int placesDeleted; // starts as 0
switch (match) {
// Handle the single item case, recognized by the ID included in the URI path
case PLACE_WITH_ID:
// Get the place ID from the URI path
String id = uri.getPathSegments().get(1);
// Use selections/selectionArgs to filter for this ID
placesDeleted = db.delete(PlaceContract.PlaceEntry.TABLE_NAME, "_id=?", new String[]{id});
break;
default:
throw new UnsupportedOperationException("Unknown uri: " + uri);
}
// Notify the resolver of a change and return the number of items deleted
if (placesDeleted != 0) {
// A place (or more) was deleted, set notification
getContext().getContentResolver().notifyChange(uri, null);
}
// Return the number of places deleted
return placesDeleted;
}
#Override
public int update(#NonNull Uri uri, ContentValues values, String selection,
String[] selectionArgs) {
// Get access to underlying database
final SQLiteDatabase db = mPlaceDbHelper.getWritableDatabase();
int match = sUriMatcher.match(uri);
// Keep track of the number of updated places
int placesUpdated;
switch (match) {
case PLACE_WITH_ID:
// Get the place ID from the URI path
String id = uri.getPathSegments().get(1);
// Use selections/selectionArgs to filter for this ID
placesUpdated = db.update(PlaceContract.PlaceEntry.TABLE_NAME, values, "_id=?", new String[]{id});
break;
// Default exception
default:
throw new UnsupportedOperationException("Unknown uri: " + uri);
}
// Notify the resolver of a change and return the number of items updated
if (placesUpdated != 0) {
// A place (or more) was updated, set notification
getContext().getContentResolver().notifyChange(uri, null);
}
// Return the number of places deleted
return placesUpdated;
}
#Override
public String getType(#NonNull Uri uri) {
throw new UnsupportedOperationException("Not yet implemented");
}
}
I am assuming that you are trying to make an app that employees would use to clock in/out by:
A) scanning their fingerprint (with the app),
and B) clicking a button "IN" or "OUT" (with the same app) ??
If so, then you don't need geofencing. Geofencing is for situations where you want something to happen automatically when a user enters a designated area.
Your situation, on the other hand, only requires that your app be aware of the phone's location when the user clicks IN/OUT.
When the user clicks IN/OUT, you would just upload the latitude and longitude, time, ID etc. and the server would determine whether the latitude or longitude is within the boundary (you can do that like this).
If they are not in the boundary, then the server would return an error... or it could be quiet about it.
You will also have to guard against fake locations.
I am new to Android and Java. The following code is to send and wait for receiving SMS. As the process may takes about 3 minutes, I need to have a progressDialog until SMS is received. Could you send me an applet to do this ?
package com.examples.TOLD;
import android.app.Activity;
import android.os.Bundle;
import android.content.Intent;
import android.telephony.SmsManager;
import android.util.Log;
import android.widget.TextView;
public class Sms extends Activity {
/** Called when the activity is first created. */
static TextView smsReceive;
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.sms);
Intent i = getIntent();
// Receiving the Data
String reg = i.getStringExtra("reg");
String port = i.getStringExtra("port");
String smsMessage =
"REG=" + reg +
"PORT=" + port;
// Show SMS sent message on screen
TextView smsSend = (TextView) findViewById(R.id.smsSend);
smsSend.setText(smsMessage);
Log.i("smsSend",String.valueOf(smsSend.getText()));
// Send SMS message
SmsManager sm = SmsManager.getDefault();
String number = "5556";
sm.sendTextMessage(number, null, smsMessage, null, null);
// Receive SMS message
smsReceive = (TextView) findViewById(R.id.smsReceive);
}
public static void updateMessageBox(String msg)
{
smsReceive.append(msg);
}
}
Here is another class to receive SMS:
package com.examples.TOLD;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.telephony.SmsMessage;
import android.util.Log;
public class SmsReceiver extends BroadcastReceiver{
public void onReceive(Context context, Intent intent)
{
Bundle bundle=intent.getExtras();
Object[] messages=(Object[])bundle.get("pdus");
SmsMessage[] sms = new SmsMessage[messages.length];
for(int n=0;n<messages.length;n++){
sms[n]=SmsMessage.createFromPdu((byte[]) messages[n]);
}
for(SmsMessage msg:sms){
String num = msg.getOriginatingAddress();
Log.i("SMS sender",num);
if (num.equals("15555215556")) {
Sms.updateMessageBox("\nFrom: " + msg.getOriginatingAddress() +
"\n" + "Message: " + msg.getMessageBody() + "\n");}
}
}
}
I think you can try to reconsider your approach. You can't expect user will be waiting for up to 3 minutes for the SMS. So you code looks right (except the part of the static method cos I explain you later), but once your message is sent, I'd show a message that your app is waiting for the message, and when the message is received in the SmsReceiver, you can communicate with the Sms activity.
But, you shouldn't use that static method to update the content of the activity for several reasons (UI can't be updated in background or most important when the SmsReceiver is fired SMS activity can even non exist). The right way would be sending an intent from the receiver. You can see a detailed step by step example in the pdf contained in this link in the section Receiving SMS messages.
I Don't think sending and receiving should be in the main thread. You can use AsyncTask to receive the message in background. you can show the dialog before starting the task and
close it after recieving
Lookup http://developer.android.com/reference/android/os/AsyncTask.html for painless background threading.
Simply display your progress dialog in OnPreExecute and dismiss it when the task reaches OnPostExecute.
I using a tutorial from tutsplus.com on building a twitter client for Android. I've built the entire application and when I run it, the following error appears in logcat for Eclipse.
android.os.NetworkOnMainThreadException -- reading a few things, it has to deal with the API level I'm calling. Currently I'm building for 4.0.3 which is API 15. After API 11, you are not allowed to do network calls in the same thread as the UI. The reason behind this is not to stall or crash the UI. Networking calls must be in an AsyncTask or Service.
Long and short of my question/problem/issue is that the tutorial maker is of no help to correct the problem, so that's why I'm here. I'm posting the code below, in hopes that someone can help me move the network portion into an AsyncTask or Service.
package com.jasonsdesign.tweetxy;
import twitter4j.ProfileImage;
import twitter4j.Twitter;
import twitter4j.TwitterException;
import twitter4j.TwitterFactory;
import twitter4j.auth.AccessToken;
import twitter4j.auth.RequestToken;
import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.database.Cursor;
import android.database.DatabaseUtils;
import android.database.sqlite.SQLiteDatabase;
import android.net.Uri;
import android.os.Bundle;
import android.provider.BaseColumns;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.ListView;
public class TweetxyActivity extends Activity implements OnClickListener {
/**developer account key for this app*/
public final static String TWIT_KEY = "";
/**developer secret for the app*/
public final static String TWIT_SECRET = "";
/**app url*/
public final static String TWIT_URL = "tweetxy-android:///";
private String LOG_TAG = "TweetxyActivity";
/**Twitter instance*/
private Twitter tweetxyTwitter;
/**request token for accessing user account*/
private RequestToken tweetxyRequestToken;
/**shared preferences to store user details*/
private SharedPreferences tweetxyPrefs;
/**main view for the home timeline*/
private ListView homeTimeline;
/**database helper for update data*/
private TweetxyDataHelper timelineHelper;
/**update database*/
private SQLiteDatabase timelineDB;
/**cursor for handling data*/
private Cursor timelineCursor;
/**adapter for mapping data*/
private UpdateAdapter timelineAdapter;
/**broadcast receiver for when new updates are available*/
private BroadcastReceiver tweetxyStatusReceiver;
//set the profile image display
ProfileImage.ImageSize imageSize = ProfileImage.NORMAL;
/*
* onCreate behaves differently on first run and subsequent runs
* - if first run take to Twitter sign in page to grant the app permission
* - subsequent runs fetch and present the user home timeline
*/
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//get the preferences
tweetxyPrefs = getSharedPreferences("TweetxyPrefs", 0);
//find out if the user preferences are set
if(tweetxyPrefs.getString("user_token", null)==null) {
//no user preferences so prompt to sign in
setContentView(R.layout.main);
//get a twitter instance for authentication
tweetxyTwitter = new TwitterFactory().getInstance();
//pass developer key and secret
tweetxyTwitter.setOAuthConsumer(TWIT_KEY, TWIT_SECRET);
//try to get request token
try
{
//get authentication request token
tweetxyRequestToken = tweetxyTwitter.getOAuthRequestToken(TWIT_URL);
}
catch(TwitterException te) { Log.e(LOG_TAG, "TE "+te.getMessage()); }
//setup button for click listener
Button signIn = (Button)findViewById(R.id.signin);
signIn.setOnClickListener(this);
}
else
{
//user preferences are set - get timeline
setupTimeline();
}
}
/**
* Click listener handles sign in and tweet button presses
*/
public void onClick(View v) {
//find view
switch(v.getId()) {
//sign in button pressed
case R.id.signin:
//take user to twitter authentication web page to allow app access to their twitter account
String authURL = tweetxyRequestToken.getAuthenticationURL();
startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(authURL)));
break;
//user has pressed tweet button
case R.id.tweetbtn:
//launch tweet activity
startActivity(new Intent(this, TweetxyTweet.class));
break;
default:
break;
}
}
/*
* onNewIntent fires when user returns from Twitter authentication Web page
*/
#Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
//get the retrieved data
Uri twitURI = intent.getData();
//make sure the url is correct
if(twitURI!=null && twitURI.toString().startsWith(TWIT_URL))
{
//is verification - get the returned data
String oaVerifier = twitURI.getQueryParameter("oauth_verifier");
//attempt to retrieve access token
try
{
//try to get an access token using the returned data from the verification page
AccessToken accToken = tweetxyTwitter.getOAuthAccessToken(tweetxyRequestToken, oaVerifier);
//add the token and secret to shared prefs for future reference
tweetxyPrefs.edit()
.putString("user_token", accToken.getToken())
.putString("user_secret", accToken.getTokenSecret())
.commit();
//display the timeline
setupTimeline();
}
catch (TwitterException te)
{ Log.e(LOG_TAG, "Failed to get access token: "+te.getMessage()); }
}
}
/**
* setupTimeline displays the user's main home Twitter timeline
*/
private void setupTimeline() {
//set the layout
setContentView(R.layout.timeline);
//setup onclick listener for tweet button
LinearLayout tweetClicker = (LinearLayout)findViewById(R.id.tweetbtn);
tweetClicker.setOnClickListener(this);
//retrieve the timeline
try
{
//get reference to the list view
homeTimeline = (ListView)findViewById(R.id.homeList);
//instantiate database helper
timelineHelper = new TweetxyDataHelper(this);
//get the database
timelineDB = timelineHelper.getReadableDatabase();
//query the database, most recent tweets first
timelineCursor = timelineDB.query("home", null, null, null, null, null, "update_time DESC");
//manage the updates using a cursor
startManagingCursor(timelineCursor);
//instantiate adapter
timelineAdapter = new UpdateAdapter(this, timelineCursor);
//apply the adapter to the timeline view
//this will make it populate the new update data in the view
homeTimeline.setAdapter(timelineAdapter);
//instantiate receiver class for finding out when new updates are available
tweetxyStatusReceiver = new TwitterUpdateReceiver();
//register for updates
registerReceiver(tweetxyStatusReceiver, new IntentFilter("TWITTER_UPDATES"));
//start the service for updates now
this.getApplicationContext().startService(new Intent(this.getApplicationContext(), TimelineService.class));
}
catch(Exception te) { Log.e(LOG_TAG, "Failed to fetch timeline: "+te.getMessage()); }
}
/**
* Class to implement broadcast receipt for new updates
*/
class TwitterUpdateReceiver extends BroadcastReceiver
{
/**
* When new updates are available, a broadcast is received here
*/
#Override
public void onReceive(Context context, Intent intent) {
//delete db rows
int rowLimit = 100;
if(DatabaseUtils.queryNumEntries(timelineDB, "home")>rowLimit) {
String deleteQuery = "DELETE FROM home WHERE "+BaseColumns._ID+" NOT IN " +
"(SELECT "+BaseColumns._ID+" FROM home ORDER BY "+"update_time DESC " +
"limit "+rowLimit+")";
timelineDB.execSQL(deleteQuery);
}
timelineCursor = timelineDB.query("home", null, null, null, null, null, "update_time DESC");
startManagingCursor(timelineCursor);
timelineAdapter = new UpdateAdapter(context, timelineCursor);
homeTimeline.setAdapter(timelineAdapter);
}
}
/*
* When the class is destroyed, close database and service classes
*/
#Override
public void onDestroy() {
super.onDestroy();
try
{
//stop the updater service
stopService(new Intent(this, TimelineService.class));
//remove receiver register
unregisterReceiver(tweetxyStatusReceiver);
//close the database
timelineDB.close();
}
catch(Exception se) { Log.e(LOG_TAG, "unable to stop service or receiver"); }
}
}
What do you need besides what https://developer.android.com/reference/android/os/AsyncTask.html provides? Do you have a specific question regarding the usage of AsyncTask?
You take the offending line and put it inside doInBackground(). If it has a result you either put the result handling code in doInBackground(), if it does not manipulate the UI. If it does make changes to the UI, you put it in onPostExecute().
Then you replace the line that threw the exception with:
new MyTask().execute(param);
Keep in mind that the code after this is executed immediately.
I don't see a need for your question to be held up, most of the issues you face at the moment are solvable through the AsyncTask use that is so well documented over Here.
I'd suggest you don't use the tutorial as a framework to your app/project but rather use it as a guide to know how to set your own project up. It'll be way better if you create your own AsyncTask and use that to get data from the network as getting network related data in a main task or most tasks besides AsynTasks is usually frowned upon due to the exceptions it throws.