I am implementing an Android app that is responsible for some data exchange with other services such as credentials. I then want to use that information to automatically fill in the input fields of other applications on the device such as Spotify.
Is there any way to fill the input fields of another app, like the username and password to remove the chore for the user to manually input it?
Also I noticed that at least on iOS, Spotify recognizes 1Password to be installed and displays a small icon next to the input fields with which I can fill the fields from the data stored in 1Password - how is this done as it seems to be another solution to my problem?
Thanks in advance
You might want to implement Autofill Service https://developer.android.com/guide/topics/text/autofill-services.html
There is a ready to use sample app which will get you started https://github.com/googlesamples/android-AutofillFramework
Android will invoke onFillRequest() method giving your service a chance to show autofill suggestions. Here is a sample code from above link:
#Override
public void onFillRequest(FillRequest request, CancellationSignal cancellationSignal, FillCallback callback) {
// Get the structure from the request
List<FillContext> context = request.getFillContexts();
AssistStructure structure = context.get(context.size() - 1).getStructure();
// Traverse the structure looking for nodes to fill out.
ParsedStructure parsedStructure = parseStructure(structure);
// Fetch user data that matches the fields.
UserData userData = fetchUserData(parsedStructure);
// Build the presentation of the datasets
RemoteViews usernamePresentation = new RemoteViews(getPackageName(), android.R.layout.simple_list_item_1);
usernamePresentation.setTextViewText(android.R.id.text1, "my_username");
RemoteViews passwordPresentation = new RemoteViews(getPackageName(), android.R.layout.simple_list_item_1);
passwordPresentation.setTextViewText(android.R.id.text1, "Password for my_username");
// Add a dataset to the response
FillResponse fillResponse = new FillResponse.Builder()
.addDataset(new Dataset.Builder()
.setValue(parsedStructure.usernameId,
AutofillValue.forText(userData.username), usernamePresentation)
.setValue(parsedStructure.passwordId,
AutofillValue.forText(userData.password), passwordPresentation)
.build())
.build();
// If there are no errors, call onSuccess() and pass the response
callback.onSuccess(fillResponse);
}
class ParsedStructure {
AutofillId usernameId;
AutofillId passwordId;
}
class UserData {
String username;
String password;
}
Related
I want my user to be able to pick an address. For my backend, I need to get the following info: street name, number, country and zip code.
I am using PlaceAutocompleteFragment fragment as mentioned here: https://developers.google.com/places/android-api/autocomplete.
When the user has selected a Place, I get the Place object as a result:
autocompleteFragment.setOnPlaceSelectedListener(new PlaceSelectionListener() {
#Override
public void onPlaceSelected(Place place) {
// Here I want to retrieve all the address details, such as
// street name, number, country etc. and send them to my backend
}
#Override
public void onError(Status status) {
//handle Error
}
});
However from the Place object I can only use place.getAddress() to get a "human readable" address line.
The iOs and JS documentations both show that you can retrieve the addressComponents(iOs) or address_components(JS) from the Place object which contains these fields (street, zipcode, etc.). However the Android documentation shows no such method for a Place object for retrieving the addressComponents.
Am I overlooking something? Is it possible that they provide this info fro iOs and JS but not for android? Or am I also maybe missing an ovious alternative?
You need to set the search parameters you want.
autocompleteFragment.setPlaceFields(Arrays.asList(Place.Field.ADDRESS,Place.Field.LAT_LNG));
There is a getAddressComponents() in Place object.
Make sure to add "Place.Field.ADDRESS" in Fields list, onActivityResultresults data will have the components of the place, otherwise it will be null.
List<Place.Field> fieldList = Arrays.asList(Place.Field.ADDRESS,
Place.Field.ADDRESS_COMPONENTS,
Place.Field.LAT_LNG, Place.Field.NAME, Place.Field.UTC_OFFSET);
Intent intent = new Autocomplete.IntentBuilder(AutocompleteActivityMode.OVERLAY
, fieldList)
.build(context);
Am developing chat application in android using Firebase with a feature that user can translate its chat to desired language.I put translation selection menu in my Chat class.Now my code is working fine to translate one text using Yandex Key but my question is how can i translate whole chat using the same scenario? Or how to get all messages in one String to Translate them.
My code for translating one message is as below:
case R.id.german:
TranslatorBackgroundTask tbt = new TranslatorBackgroundTask(getApplication());
String translationResult = String.valueOf(tbt.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR, message, "en-de"));
textView.setText(TranslatorBackgroundTask.result);
Why not just use List object for storing all texts and execute translation function repeatedly? Some thing like this
List<String> texts = new ArrayList<>();
// pass texts
List<String> translatedTexts = translate(texts);
public void translate(List<String>) {
List<String> resultTexts = new ArrayList<>();
//apply your logic for translating each text with the for each method
return resultTexts;
}
I am developing an android application where older kids can pick up younger kids and walk to school. With the application the authenticated (email and password) younger kid can choose between three adresses to get picked up. As of right now my realtime database looks like this:
I want to retrieve the different addresses and the users who picked the addresses. I am thinking I have to use recyclerview to get the data, but I am unsure on if it is possible to do with my database structure.
Using the FirebaseUI database package makes it simple to bind data from the Firebase Realtime Database to your app's UI. Specifically using FirebaseUI with indexed data is applicable for your current database structure.
For example, you'd use something similar to:
// keyQuery - the Firebase location containing the list of keys to be found in dataRef
// dataRef - the Firebase location to watch for data changes. Each key found at
// keyRef's location represents a list item.
Query keyQuery = FirebaseDatabase.getInstance().getReference("/Addresses/Street 10/users");
DatabaseReference dataRef = FirebaseDatabase.getInstance().getReference("/User");
FirebaseRecyclerOptions<User> options = new FirebaseRecyclerOptions.Builder<User>()
.setIndexedQuery(keyQuery, dataRef, User.class)
.build();
Where your User class is:
public class User {
private String username;
public User() {}
public String getUsername() {
return this.username;
}
public void setUsername(String username) {
this.username = username;
}
// ...
}
You can then use the above created options variable to create a FirebaseRecyclerAdapter instance and then call startListening() on it*.
Using FirebaseUI in this way will automatically handle matching the keys under /Addresses/Street 10/users to the /User node.
* Version 2.x of FirebaseUI uses FirebaseIndexRecyclerAdapter instead and starts listening automatically so doesn't require a startListening() call. The above example is applicable for version 3.0, see FirebaseUI 3.0 upgrade guide.
Following on from my previous answer, this one should accommodate your requirement to create a list of all addresses and their associated users, which may be closer to what you're looking for.
Again you can use the FirebaseUI database package to simplify the RecyclerView creation.
You'll need to start denormalizing your data, so your data structure should also include usernames in the addresses node:
{
"Addresses" : {
"Street 10" : {
"name" : "Street 10",
"users" : {
"VAzdMWafK6cyhmJnOI4br5xiQg93" : "John"
}
}
},
"User" : {
"VAzdMWafK6cyhmJnOI4br5xiQg93" : {
"username" : "John",
"address" : "Street 10"
}
}
}
Note: you only need to add user IDs to their chosen address (and remove the node if they change selection), so don't use "VAzdMWafK6cyhmJnOI4br5xiQg93" : false for addresses the user has not selected as this could cause confusion.
Then you can use:
Query query = FirebaseDatabase.getInstance().getReference("/Addresses");
FirebaseRecyclerOptions<Address> options = new FirebaseRecyclerOptions.Builder<Address>()
.setQuery(query, Address.class)
.build();
Where Address is something like:
public class Address {
private String name;
private Map<String, String> users;
public Address() {}
public Map<String, String> getUsers() {
return this.users;
}
// ...
}
And create a FirebaseRecyclerAdapter instance from the options variable. Then when binding the viewholder in the adapter, you can access the users map to list each user that has selected this address, without the need to load the entire User object unnecessarily.
This pattern is called denormalization and is the suggested approach when using NoSQL databases (like Firebase Realtime Database). The main downside to this is data duplication: so for example, when a user changes their selected address, you'll need to change:
The address value under the user, and
the users list under the address.
Likewise, if a user is allowed to change their username, you'll need to update the username under their chosen address as well as in the user's node.
For details on dealing with this, see this answer which explains a number of methods (although the examples are in JavaScript, the premise still applies).
I'm measuring my Android app checkout performance by using the google-analytics SDK. I created a Wrapper that I use in order to send hits (and it works) and exceptions (it works as well). I just can't make it work with eCommerce data.
In order to send ecommerce data i create a product and a productAction
Product product = new Product()
.setId(ID)
.setCategory(category)
.setBrand(brandID)
.setCustomDimension(1, typology)
.setCustomDimension(2, currency)
.setPrice(getTotal())
.setQuantity(1);
// Add the step number and additional info about the checkout to the action.
ProductAction productAction = new ProductAction(ProductAction.ACTION_PURCHASE)
.setCheckoutStep(4)
.setCheckoutOptions("Perform payment");
and then
sendEcommerceCheckoutStep(product, productAction, "performPayment", getApplicationContext())
the body of said method is
public void sendEcommerceCheckoutStep(Product product, ProductAction productAction, String checkoutStepName, Context context) {
HitBuilders.ScreenViewBuilder builder = new HitBuilders.ScreenViewBuilder()
.addProduct(product)
.setProductAction(productAction)
.addImpression(product, checkoutStepName);
mTracker.setScreenName(checkoutStepName);
mTracker.send(builder.build());
mTracker.setScreenName(null);
}
Now, I'd expect data to flow through analytics (and it does, I checked the adb logs) but I can't see it in analytics web interface.
This is what I see on analytics web interface:
As you can see the only column which got data is the "Cart-to-Detail Rate" one. But how can I have a cart-to-detail rate if I don't have any data in any other column?
This was the "product performance" screen. This is the "Product list performance":
all other columns are 0 as well. Why did it list the "add to cart" actions but not the others?
The following code is working on my app. I have followed the official transaction guide.
I found a few differences with yours. E.g. the name of the screen name, I don't set it to null later, I don't set the checkout step, I don't set custom dimensions nor impressions.
Feel free to try it:
public void trackPurchase(#NonNull TrackingPurchase trackingPurchase) {
HitBuilders.ScreenViewBuilder builder = new HitBuilders.ScreenViewBuilder();
for (TrackingProduct trackingProduct : trackingPurchase.getTrackingProducts()) {
builder.addProduct(this.createProduct(trackingProduct));
}
builder.setProductAction(this.createProductAction(trackingPurchase));
googleAnalyticsTracker.setScreenName("transaction");
googleAnalyticsTracker.set("&cu", "USD");
googleAnalyticsTracker.send(builder.build());
}
#NonNull
private Product createProduct(#NonNull TrackingProduct trackingProduct) {
return new Product()
.setId(trackingProduct.getSku())
.setName(trackingProduct.getName())
.setCategory(trackingProduct.getCategory())
.setPrice(trackingProduct.getPrice())
.setQuantity(trackingProduct.getQuantity());
}
#NonNull
private ProductAction createProductAction(#NonNull TrackingPurchase trackingPurchase) {
return new ProductAction(ProductAction.ACTION_PURCHASE)
.setTransactionId(trackingPurchase.getSaleId())
.setTransactionAffiliation("Android App")
.setTransactionRevenue(trackingPurchase.getRevenue())
.setTransactionTax(0)
.setTransactionShipping(trackingPurchase.getShippingCost())
.setTransactionCouponCode(trackingPurchase.getCouponCode());
}
TrackingPurchase is a class that just contains the various TrackingProduct which are data to be tracked.
I can see this tracked by checking here:
For example, you will see revenue and top sellers.
I'm using Google's mobile backend starter for a project and I want to set the key name myself for some of entities instead of using the auto-generated one.
If I were doing this without the backend I could do something like it describes in the datastore documentation which creates an employee entity with the key name "asalieri":
Entity employee = new Entity("Employee", "asalieri");
Here's the code I'm using to create the entity. I've been trying to use the CloudEntity.setId() function. Upc is a string and it doesn't work when I use a hardcoded string either.
CloudEntity avg = new CloudEntity("Aggregate");
avg.setId(upc);
avg.put("averagePrice", sum/count);
insertAverage(avg);
private void insertAverage(CloudEntity avg) {
CloudCallbackHandler<CloudEntity> handler = new CloudCallbackHandler<CloudEntity>() {
#Override
public void onComplete(final CloudEntity result) {
Toast.makeText(AddProduct.this, "Average updated.", Toast.LENGTH_LONG).show();
}
#Override
public void onError(final IOException exception) {
handleEndpointException(exception);
}
};
// execute the insertion with the handler
getCloudBackend().insert(avg, handler);
}
When I run the app everything works fine except that the new entity doesn't have the custom ID that I set.
The only thing I can think of is that setId() isn't supposed to do what I think it does but I've been digging through the code and haven't been able to find another way to do what I want.
Does anyone know why this isn't working?
I'm a Googler on the MBS project. I recreated your issue and first glance shows this as a bug on our side. I'll edit my response with updates.
Would this workaround be ok until we push a fix?
avg.put("samId", upc)