I cannot see other online members in Firebase real-time - android-studio

I won't be able to post all code here but the key areas only. I am trying to see members online but from the code I can only see myself(as attached screenshot). Before this I would as well want to use some sort of filter based on fields like gender, age group(one example will show me what to do) to show me who is online so I can proceed from there.
I am using real-time database for the location and online presence as well as Firestore for all other details.
Below is the code in question, my real-time database responds well to it from the console but only once, i.e. it shows online once and after going to the listOnline class and back to MainActivity class, the status remains offline.
The user to be displayed too I would like using their usernames NOT emails. Yes I tried that and somehow the whole thing had errors nearly everywhere
private void displayLocation() {
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED
&& ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
return;
}
mLastLocation = LocationServices.FusedLocationApi.getLastLocation(mGoogleApiCLient);
if (mLastLocation != null) {
//Update Firebase
locations.child(Objects.requireNonNull(FirebaseAuth.getInstance().getCurrentUser()).getUid()).
setValue(new Tracking(FirebaseAuth.getInstance().getCurrentUser().getEmail(),
FirebaseAuth.getInstance().getCurrentUser().getUid(),
String.valueOf(mLastLocation.getLatitude()),
String.valueOf(mLastLocation.getLongitude()),
FirebaseAuth.getInstance().getCurrentUser().getDisplayName()));
} else {
Snackbar snackbar = Snackbar.make(relativeLayout, "Location Not Found", Snackbar.LENGTH_LONG);
snackbar.setActionTextColor(Color.RED);
snackbar.show();
}
}
private void updateList() {
mFireAdapter = new FirebaseRecyclerAdapter<User, ListOnlineViewHolder>(User.class,
R.layout.user_layout, ListOnlineViewHolder.class, counterRef) {
#Override
protected void populateViewHolder(ListOnlineViewHolder viewHolder, final User model, int position) {
if (model.getEmail().equalsIgnoreCase(Objects.requireNonNull(FirebaseAuth.getInstance().getCurrentUser()).getEmail())) {
System.out.println("Current user");
viewHolder.username.setText(String.valueOf(
model.getUserName()));
viewHolder.username.append("(Me)");
}else {
viewHolder.username.setText(model.getUserName());
}
//implement update click listener
viewHolder.itemClickListenener = new ItemClickListenener() {
#Override
public void onClick(View view, int position) {
//cant click current user logged in
//sending information of other users not one logged in
if (!model.getEmail().equals(FirebaseAuth.getInstance().getCurrentUser().getEmail())) {
Intent in = new Intent(getApplicationContext(), MapTracking.class);
in.putExtra("email", model.getEmail());
in.putExtra("latitude", mLastLocation.getLatitude());
in.putExtra("Longitude", mLastLocation.getLongitude());
startActivity(in);
}
}
};
}
};
mFireAdapter.notifyDataSetChanged();
listOnline.setAdapter(mFireAdapter);
}
From a class called tracking, the code is as below
public class Tracking {
private String mEmail,lat,lng,userName;
public Tracking() {
}
public Tracking(String email, String uid, String lat, String lng,String userName) {
this.mEmail = email;
this.lat = lat;
this.lng = lng;
this.userName = userName;
}
Am running with a real device, so below is the code from run
D/Surface: Surface::connect(this=0x7309a14000,api=1)
D/Surface: Surface::setBufferCount(this=0x7309a14000,bufferCount=3)
Surface::allocateBuffers(this=0x7309a14000)
I/System.out: Current user
D/LOG: is Online
D/Surface: Surface::disconnect(this=0x730a9ca000,api=1)
V/PhoneWindow: DecorView setVisiblity: visibility = 4, Parent = android.view.ViewRootImpl#6b16f27, this = DecorView#a027f28[MainActivity]
screenshot with that message below displaying only me and not the others online
real-time database
firestore

Related

How to get a B2CUser from a IAuthenticationResult when using MSAL in Android

I am using MSAL with Android in B2C multiuser mode. The code I am following is from this example. It shows how to get a list of B2CUsers from a list of accounts:
private void loadAccounts() {
if (b2cApp == null) {
return;
}
b2cApp.getAccounts(new IPublicClientApplication.LoadAccountsCallback() {
#Override
public void onTaskCompleted(final List<IAccount> result) {
users = B2CUser.getB2CUsersFromAccountList(result);
updateUI(users);
}
#Override
public void onError(MsalException exception) {
displayError(exception);
}
});
}
But I also need to get the specific B2CUser after authenticating:
AcquireTokenParameters parameters = new AcquireTokenParameters.Builder()
.startAuthorizationFromActivity(getActivity())
.fromAuthority(B2CConfiguration.getAuthorityFromPolicyName(policyListSpinner.getSelectedItem().toString()))
.withScopes(B2CConfiguration.getScopes())
.withPrompt(Prompt.LOGIN)
.withCallback(getAuthInteractiveCallback())
.build();
b2cApp.acquireToken(parameters);
Which gives me a IAccount after from the authenticationResult:
#Override
public void onSuccess(IAuthenticationResult authenticationResult) {
/* Successfully got a token, use it to call a protected resource - MSGraph */
Log.d(TAG, "Successfully authenticated");
/* display result info */
displayResult(authenticationResult);
/* Reload account asynchronously to get the up-to-date list. */
loadAccounts();
}
But I can't seem to turn that into a B2CUser or get the ID from it as the:
iAuthenticationResult.getAccount().getId()
seems to return the policy appended to it and I cannot get the displayName either.

Running a long operation within an event handler

I need to run some address validation on Customer Location addresses using a 3rd party API to determine if the address is residential or commercial. This validation should run whenever an address field is changed. In other words, the validation should be run in the Address_RowUpdated event handler.
Because the function is calling a 3rd party API, I believe that it should be done in a separate thread, using PXLongOperation so that it does not hold up address saving and fails gracefully if the API is unavailable or returns an error.
However, I am not sure if the architecture of running a long operation within an event handler is supported or if a different approach would be better.
Here is my code.
public class CustomerLocationMaint_Extension : PXGraphExtension<CustomerLocationMaint>
{
protected virtual void Address_RowUpdated(PXCache sender, PXRowUpdatedEventArgs e)
{
PX.Objects.CR.Address row = (PX.Objects.CR.Address)e.Row;
if (row != null)
{
Location location = this.Base.Location.Current;
PXCache locationCache = Base.LocationCurrent.Cache;
PXLongOperation.StartOperation(Base, delegate
{
RunCheckResidential(location, locationCache);
});
this.Base.LocationCurrent.Cache.IsDirty = true;
}
}
protected void RunCheckResidential(Location location, PXCache locationCache)
{
string messages = "";
PX.Objects.CR.Address defAddress = PXSelect<PX.Objects.CR.Address,
Where<PX.Objects.CR.Address.addressID, Equal<Required<Location.defAddressID>>>>.Select(Base, location.DefAddressID);
FValidator validator = new FValidator();
AddressValidationReply reply = validator.Validate(defAddress);
AddressValidationResult result = reply.AddressResults[0];
bool isResidential = location.CResedential ?? false;
if (result.Classification == FClassificationType.RESIDENTIAL)
{
isResidential = true;
} else if (result.Classification == FClassificationType.BUSINESS)
{
isResidential = false;
} else
{
messages += "Residential classification is: " + result.Classification + "\r\n";
}
location.CResedential = isResidential;
locationCache.Update(location);
Base.LocationCurrent.Update(location);
Base.Actions.PressSave();
// Display relevant messages
if (reply.HighestSeverity == NotificationSeverityType.SUCCESS)
String addressCorrection = validator.AddressCompare(result.EffectiveAddress, defAddress);
if (!string.IsNullOrEmpty(addressCorrection))
messages += addressCorrection;
}
PXSetPropertyException message = new PXSetPropertyException(messages, PXErrorLevel.Warning);
PXLongOperation.SetCustomInfo(new LocationMessageDisplay(message));
//throw new PXOperationCompletedException(messages); // Shows message if you hover over the success checkmark, but you have to hover to see it so not ideal
}
public class LocationMessageDisplay : IPXCustomInfo
{
public void Complete(PXLongRunStatus status, PXGraph graph)
{
if (status == PXLongRunStatus.Completed && graph is CustomerLocationMaint)
{
((CustomerLocationMaint)graph).RowSelected.AddHandler<Location>((sender, e) =>
{
Location location = e.Row as Location;
if (location != null)
{
sender.RaiseExceptionHandling<Location.cResedential>(location, location.CResedential, _message);
}
});
}
}
private PXSetPropertyException _message;
public LocationMessageDisplay(PXSetPropertyException message)
{
_message = message;
}
}
}
UPDATE - New Approach
As suggested, this code now calls the LongOperation within the Persist method.
protected virtual void Address_RowUpdated(PXCache sender, PXRowUpdatedEventArgs e)
{
PX.Objects.CR.Address row = (PX.Objects.CR.Address)e.Row;
if (row != null)
{
Location location = Base.Location.Current;
LocationExt locationExt = PXCache<Location>.GetExtension<LocationExt>(location);
locationExt.UsrResidentialValidated = false;
Base.LocationCurrent.Cache.IsDirty = true;
}
}
public delegate void PersistDelegate();
[PXOverride]
public virtual void Persist(PersistDelegate baseMethod)
{
baseMethod();
var location = Base.Location.Current;
PXCache locationCache = Base.LocationCurrent.Cache;
LocationExt locationExt = PXCache<Location>.GetExtension<LocationExt>(location);
if (locationExt.UsrResidentialValidated == false)
{
PXLongOperation.StartOperation(Base, delegate
{
CheckResidential(location);
});
}
}
public void CheckResidential(Location location)
{
CustomerLocationMaint graph = PXGraph.CreateInstance<CustomerLocationMaint>();
graph.Clear();
graph.Location.Current = location;
LocationExt locationExt = location.GetExtension<LocationExt>();
locationExt.UsrResidentialValidated = true;
try
{
// Residential code using API (this will change the value of the location.CResedential field)
} catch (Exception e)
{
throw new PXOperationCompletedWithErrorException(e.Message);
}
graph.Location.Update(location);
graph.Persist();
}
PXLongOperation is meant to be used in the context of a PXAction callback. This is typically initiated by a menu item or button control, including built-in actions like Save.
It is an anti-pattern to use it anytime a value changes in the web page. It should be used only when a value is persisted (by Save action) or by another PXAction event handler. You should handle long running validation when user clicks on a button or menu item not when he changes the value.
For example, the built in Validate Address feature is run only when the user clicks on the Validate Address button and if validated requests are required it is also run in a Persist event called in the context of the Save action to cancel saving if validation fails.
This is done to ensure user expectation that a simple change in a form/grid value field doesn't incur a long validation wait time that would lead the user to believe the web page is unresponsive. When the user clicks on Save or a specific Action button it is deemed more reasonable to expect a longer wait time.
That being said, it is not recommended but possible to wrap your PXLongOperation call in a dummy Action and asynchronously click on the invisible Action button to get the long operation running in the proper context from any event handler (except Initialize):
using PX.Data;
using System.Collections;
namespace PX.Objects.SO
{
public class SOOrderEntry_Extension : PXGraphExtension<SOOrderEntry>
{
public PXAction<SOOrder> TestLongOperation;
[PXUIField(DisplayName = "Test Long Operation", Visible = false, Visibility = PXUIVisibility.Invisible)]
[PXButton]
public virtual IEnumerable testLongOperation(PXAdapter adapter)
{
PXLongOperation.StartOperation(Base, delegate ()
{
System.Threading.Thread.Sleep(2000);
Base.Document.Ask("Operation Done", MessageButtons.OK);
});
return adapter.Get();
}
public void SOOrder_OrderDesc_FieldUpdated(PXCache sender, PXFieldUpdatedEventArgs e)
{
if (!PXLongOperation.Exists(Base.UID))
{
// Calling Action Button asynchronously so it can run in the context of a PXAction callback
Base.Actions["TestLongOperation"].PressButton();
}
}
}
}

update table in Azure Mobile Service

How to update particular record in azure mobile Service. For Example I have a table in azure called country having two columns
country_id
country_name
If I want to update the record with country_id=5 from USA to United State of America. How to Perform this.
//Global Variable
private MobileServiceCollection<country, country> items;
private IMobileServiceTable<country> todoTable = App.MobileService.GetTable<country>();
class country
{
public string id { get; set; }
public string country_name { get; set; }
public int country_id { get; set; }
}
private async void btnUpdate_Click(object sender, RoutedEventArgs e)
{
var change = await todoTable
.Where(todoItem => todoItem.country_name == tboxcName.Text)
.ToListAsync();
await todoTable.UpdateAsync(change);
}
The above code I tried from this post, but did not find out.
You might want to try this:
private async void btnUpdate_Click(object sender, RoutedEventArgs e)
{
var change = await todoTable
.Where(todoItem => todoItem.id.Equals(tboxcName.Text))
.ToListAsync();
if(change != null){
var toChange= change.First();
toChange.country_name="United State of America";
await todoTable.UpdateAsync(toChange);
}
else{
// you have nothing to change, you might throw an exception
}
}
In the textbox you should enter the id you want to update, in your case it's 5. Then I make a linq query selecting all the items with Id "5", this gets me a list.
I check if the list is not void, you would want to threat the case when the list is null. If it's not null I take the first element (as you are in the mobile services the id field is unique in the database, so you don't have to threat this boundary case (although if you really want to be sure it's always better to do it)).
The first element in the list will have the ID=5, so we change the object updating it's country name to "United States of America" (in your case, you don't care of the previous value, as you are updating a specific ID). Then you update this item. The mobile service API will then issue a patch request, and the database will patch it according to the Object ID.
Hope this helps!
Try with this C# code!
private async void btnUpdate_Click(object sender, RoutedEventArgs e)
{
var filteredRecords = await todoTable.Where(
todoItem => todoItem.country_id == 5)
.ToListAsync();
foreach (var item in filteredRecords)
{
item.country_name="United States of America";
await todoTable.UpdateAsync(item);
}
}

How can I get the user_id from the user currently logged in?

I'm trying to get a private Playlist from the user currently logged in into the app.
SpotifyApi api = new SpotifyApi();
api.setAccessToken(response.getAccessToken());
SpotifyService spotify = api.getService();
Playlist playlist = spotify.getPlaylist(user_id, playlist_id);
How can I get user_id?
EDIT
I tried this code:
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == REQUEST_CODE) {
AuthenticationResponse response = AuthenticationClient.getResponse(resultCode, data);
if (response.getType() == AuthenticationResponse.Type.TOKEN) {
SpotifyApi api = new SpotifyApi();
api.setAccessToken(response.getAccessToken());
SpotifyService spotify = api.getService();
User user = spotify.getMe();
Log.d("TAG", user.id);
}
}
super.onActivityResult(requestCode, resultCode, data);
}
This gives me an error:
java.lang.RuntimeException: Failure delivering result ResultInfo{who=null, request=1337, result=-1, data=Intent { (has extras) }} to activity {de.test.spotifytest/de.test.spotifytest.activities.MainActivity}: retrofit.RetrofitError
  
            
I had to get the user object in an AsyncTask because it isn't possible to perform network actions on the main thread. The same applies to getting the users playlists.
private class MyTask extends AsyncTask<String, Integer, Pager<Playlist>>{
#Override
protected Pager<Playlist> doInBackground(String... params) {
Pager<Playlist> playlists = spotify.getPlaylists(spotify.getMe().id);
return playlists;
}
#Override
protected void onPostExecute(Pager<Playlist> playlistPager) {
//do something with the playlists
}
}
On main thread:
new MyTask().execute("");
I'm not sure what library you're using, but it looks like the spotify-web-api-android wrapper.
If so, you can retrieve the current user's user ID by calling the Get Current User's Profile endpoint using SpotifyService's getMe() method. getMe() will return a User object that has a member called id.
Update: It seems the issue may not be related to the wrapper, but rather a general Android issue. This Stack Overflow question seems related.
Adding a check to see if the resultCode isn't RESULT_CANCELED before entering the if block may solve this.
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (resultCode != RESULT_CANCELED && resultCode == REQUEST_CODE) {
AuthenticationResponse response = AuthenticationClient.getResponse(resultCode, data);
...
}
}
Others use an additional resultCode == RESULT_OK, which to my understanding is valid as well.

Is WCF Service EntitySetRights.AllRead Secure?

I have the following code inside MyDataService.svc.cs (This is an example from DevExpress):
namespace MyDataService {
[System.ServiceModel.ServiceBehavior(IncludeExceptionDetailInFaults = true)]
[JSONPSupportBehavior]
public class DataService : DataService<TestDataEntities>, IServiceProvider {
public static void InitializeService(DataServiceConfiguration config) {
config.SetEntitySetAccessRule("*", EntitySetRights.AllRead);
config.DataServiceBehavior.MaxProtocolVersion = DataServiceProtocolVersion.V3;
}
public object GetService(Type serviceType) {
if (serviceType == typeof(IDataServiceStreamProvider)) {
return new ImageStreamProvider();
}
return null;
}
protected override void OnStartProcessingRequest(ProcessRequestArgs args) {
CustomBasicAuth.Authenticate(HttpContext.Current);
if (HttpContext.Current.User == null)
throw new DataServiceException(401, "Invalid login or password");
base.OnStartProcessingRequest(args);
}
}
}
So while this is will check the Entity for a username and password, how safe is it that config.SetEntitySetAccessRule is set to AllRead. Wouldn't someone just be able to see this information on a url such as www.website.com/MyDataService.svc/Customer (where Customer is the table). If this is not so can someone please fill in the conceptual gap I am facing. Thanks!
You are correct that all entities will be returned when queried - AllRead just disallows insert updates and deletes.
You will need to use Query Interceptor to add your logic to restrict users to the set of data they have permission to view, for example adding a check user id to the query.

Resources