#Override
public void startClient(final Callback callback) {
SmsRetrieverClient client = SmsRetriever.getClient(context);
client.startSmsRetriever();
Task<Void> task = client.startSmsRetriever();
task.addOnSuccessListener(new OnSuccessListener<Void>() {
#Override
public void onSuccess(Void aVoid) {
callback.onSuccess();
}
});
task.addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
callback.onFail(e);
}
});
}
The code above is the suggested way Google encourages to use their SMS Reytriever API. This method is meant to start a client before the BroadcastReceiver looks for incoming sms messages. The problem here is that onSuccess and onFailure are never called, none of them, and only happens with a Android emulators. I put some breakpoints and logs to confirmed this, the client never notifies back what happened.
This is not a hash problem since this is only related to the initialization of the SmsRetrieverClient.
I'm really confused and don't know what's happening. To never notify a listener is a behaviour nobody would expect, I'm even thinking that this problem might be related to other factors since I recenlty formatted my computer and re-installed latest Android Studio, because before that this code was working on both emulators and physical devices.
Try removing the redundant client.startSmsRetriever(); in the second line.
Make sure the play services version on your emulator/device is > 10.2.0
You can check the play services version using -
private static final String MIN_SUPPORTED_PLAY_SERVICES_VERSION = "10.2";
public static boolean isSmsRetrieverApiAvailable(Context context) {
if (!isPlayServicesAvailable(context)) {
return false;
}
try {
String playServicesVersionName = context.getPackageManager().getPackageInfo(GoogleApiAvailability.GOOGLE_PLAY_SERVICES_PACKAGE, 0).versionName; // should be >10.2.0
return playServicesVersionName.compareTo(MIN_SUPPORTED_PLAY_SERVICES_VERSION) > 0;
} catch (PackageManager.NameNotFoundException e) {
return false;
}
}
private static boolean isPlayServicesAvailable(Context context) {
GoogleApiAvailability googleApiAvailability = GoogleApiAvailability.getInstance();
int resultCode = googleApiAvailability.isGooglePlayServicesAvailable(context);
return resultCode == ConnectionResult.SUCCESS;
Related
I have a functioning instant app and I've successfully incorporated the SMS Retriever API in several apps, but the two don't seem to function together. Is there a way to make them function together, or does there exist documentation about this not being supported?
public class SmsClient {
private SmsReceiver smsReceiver;
public interface GoogleTaskListener extends OnSuccessListener<Void>, OnFailureListener {
}
public SmsClient(#NonNull VerificationCodeListener verificationCodeListener,
int codeLength) {
this.smsReceiver = new SmsReceiver(verificationCodeListener, codeLength);
}
public void attach(Context context) {
SmsRetrieverClient client = SmsRetriever.getClient(context);
Task<Void> startSmsReceiverTask = client.startSmsRetriever();
GoogleTaskListener googleTaskListener = new GoogleTaskListener() {
#Override
public void onSuccess(Void v) {
Timber.i("Sms task succeeded!");
}
#Override
public void onFailure(#NonNull Exception e) {
Timber.e("Sms task failed."); //Message "17: API: SmsRetriever.API is not available on this device."
}
};
startSmsReceiverTask.addOnSuccessListener(googleTaskListener);
startSmsReceiverTask.addOnFailureListener(googleTaskListener);
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(SmsRetriever.SMS_RETRIEVED_ACTION);
context.registerReceiver(smsReceiver, intentFilter);
}
public void detach(Context context) {
context.unregisterReceiver(smsReceiver);
}
}
When starting the SMS Retriever with startSmsRetriever() in a regular app, onSuccess is called.
When attempting to start the SMS Retriever in the same application run as an Instant App, onFailure is called with the error message 17: API: SmsRetriever.API is not available on this device.
Ultimately, we're hoping to have a one-time-password delivered by SMS automatically processed by a running instant app to verify a session. Any information on the subject would be helpful.
I'm currently running this in the Pixel 3 (API 28) emulator.
As TWL commented, it does work. It just doesn't work in the emulator.
I'm migrating from the old Android Places API to either the new one or the compatibility library, in both approaches the auto prediction search works, but getting more details from the ID of the selected location appears to never complete.
I started with the compatibility library, the initial autoPrediction lookup works as expected. Suggesting the API key and account are fine. But getPlaceByID failed to finish.
I've switched to the new API instead, again, the new FindAutocompletePredictions works, but the fetchPlaces task never finishes.
I've boiled the code down to manually putting an ID in, only asking for LatLong, and having all the available listeners with breakpoints. They are never hit.
List<Place.Field> placeFields = Arrays.asList(Place.Field.LAT_LNG);
FetchPlaceRequest request = FetchPlaceRequest.builder("EhtHbGFzZ293IFN0cmVldCwgR2xhc2dvdywgVUsiLiosChQKEgmvXKElzUWISBFN3LArF1aEERIUChIJqZHHQhE7WgIReiWIMkOg-MQ", placeFields)
.build();
placesClient.fetchPlace(request).addOnCompleteListener(new OnCompleteListener<FetchPlaceResponse>() {
#Override
public void onComplete(#NonNull Task<FetchPlaceResponse> task) {
System.out.println("");
}
}).addOnCanceledListener(new OnCanceledListener() {
#Override
public void onCanceled() {
System.out.println("");
}
}).addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
System.out.println("");
}
}).addOnSuccessListener(new OnSuccessListener<FetchPlaceResponse>() {
#Override
public void onSuccess(FetchPlaceResponse fetchPlaceResponse) {
System.out.println("");
}
});
I would expect to hit one of the listeners and see a place, or some reason for it to fail. Or, at least something in the logcat to say what's going on.
Use
public Task<TResult> addOnCompleteListener(#NonNull OnCompleteListener<TResult> var1)
I am upgrading the in-app billing in my app from Version 3 to newer code. Version 3 is working fine and it production in my app right now but I've read it will be deprecated eventually.
When I try to test the purchase flow using a static product id (android.test.purchased), the BillingResult result code only returns -1 with a debug message of "Service connection is disconnected". AFAIK, there is no service connection in the newer library but there was in Version 3.
If I use a real in-app product code it tells me I've already purchased it, which is correct but I need to test the actual purchase flow.
I am testing this on an actual device (Pixel 3 XL), not the emulator. I've tried testing it on a separate device that is logged in with a test account (not developer) but I get the same results.
UPDATE: I setup a real (test) in-app managed product in the Developer Console, then installed my app on a device that is logged in with a test (non-developer) account and I'm still getting the "Service connection is disconnected" error. I feel it's something outside of the code but not sure what.
UPDATE 2: I created a new project with nothing in it except the billing code and it worked so there's something in my app that is causing it to break.
UPDATE 3: I created a new project and imported the code from the broken app into it and still getting the same error message. I feel, now, there's something with my package name and Google's servers that's returning the error message.
UPDATE 4: I created a blank project but gave it the same package name as my broken app and the billing worked, so it's not the package name. Now my guess is there's something from the old AIDL billing code (Version 3) that is interfering.
SOLUTION!!! in the application node in the AndroidManifest.xml I had this: tools:node="replace". Removed that attribute and billing now works.
mBillingClient = BillingClient.newBuilder(this).enablePendingPurchases().setListener(this).build();
mBillingClient.startConnection(new BillingClientStateListener() {
#Override
public void onBillingSetupFinished(BillingResult billingResult) {
if (billingResult.getResponseCode() == OK) {
final Purchase.PurchasesResult purchasesResult = mBillingClient.queryPurchases(BillingClient.SkuType.INAPP);
if (purchasesResult.getResponseCode() == OK) {
final List<Purchase> purchases = purchasesResult.getPurchasesList();
for (final Purchase purchase : purchases) {
}
}
}
}
#Override
public void onBillingServiceDisconnected() {
CommonUtils.showToast(mActivity, "disconnected");
}
});
mUnlockPremiumButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
final List<String> skuList = new ArrayList<> ();
skuList.add(getString(R.string.inapp_premium_product_id));
final SkuDetailsParams.Builder params = SkuDetailsParams.newBuilder()
.setSkusList(skuList)
.setType(BillingClient.SkuType.INAPP);
mBillingClient.querySkuDetailsAsync(params.build(),
new SkuDetailsResponseListener() {
#Override
public void onSkuDetailsResponse(BillingResult billingResult, List<SkuDetails> skuDetailsList) {
for (SkuDetails skuDetails : skuDetailsList) {
if (getString(R.string.inapp_premium_product_id).equals(skuDetails.getSku())) {
final BillingFlowParams flowParams = BillingFlowParams.newBuilder()
.setSkuDetails(skuDetails)
.build();
final BillingResult result = mBillingClient.launchBillingFlow(mActivity, flowParams);
if (result.getResponseCode() == ITEM_ALREADY_OWNED)
{
CommonUtils.showToast(mActivity, getString(R.string.alert_purchased));
}
else if (result.getResponseCode() != OK)
{
//always returns a getResponseCode of -1 (service disconnected)
}
}
}
}
});
}
});
As the error clearly indicates, the Billing Client is disconnected due to the following possible reasons.
You started the connection but the connection has not finished the setup yet.
Possible race condition since startConnection is an asynchronous process. You can use
billingClient.isReady() to check if it is available.
Your app may have lost the connection/internet after starting it.
Your device/emulator does not support Google Play Services.
The following is a working code in Billing API 3.0 with Android Version Targeted SDK 28.
As documented in Billing API Error Handling section (https://developer.android.com/google/play/billing/integrate) if the connection is lost, app must be responsible to reestablish the connection. I would recommend to use a Singleton class that holds the Billing API and use billingClient.isReady() method to check if the connection is successful, if not attempt to reestablish it. Provided you add logging in the BillingClientStateListener class override methods. I am skipping that code because it is straight forward and well documented in the link I provided above.
public class ApplicationBillingClient
{
static ApplicationBillingClient applicationBillingClient= null;
private static BillingClient billingClient;
private ApplicationBillingClient() {}
private static boolean isInitialized()
{
return applicationBillingClient != null && billingClient != null;
}
private static void initialize(Context applicationContext)
{
try
{
if(applicationContext != null)
{
applicationBillingClient = new ApplicationBillingClient();
BillingClient.Builder builder= BillingClient.newBuilder(applicationContext);
builder.setListener(new PurchaseActivityListener());
builder.enablePendingPurchases();
billingClient = builder.build();
}
LogUtil.info("Initializing the Billing Client");
}
catch (Exception ex)
{
LogUtil.error("Error while initializing billing client", ex);
}
}
public static ApplicationBillingClient getInstance(Context applicationContext)
{
if(isInitialized() == false)
{
initialize(applicationContext);
}
return applicationBillingClient;
}
public void startConnection()
{
billingClient.startConnection(new StateListener());
}
public boolean isReady()
{
return billingClient.isReady();
}
public void getMonthlySubscription()
{
try
{
if(billingClient.isReady())
{
SkuDetailsParams.Builder skuBuilder = SkuDetailsParams.newBuilder();
skuBuilder.setType(BillingClient.SkuType.SUBS);
skuBuilder.setSkusList(Arrays.asList(new String[]{MONTHLY_BILLING_SUBSCRIPTION_SKU}));
SkuDetailsParams params = skuBuilder.build();
billingClient.querySkuDetailsAsync(params, new SkuDetailsListener());
}
}
catch (Exception ex)
{
LogUtil.error("Error while querying async SKU for Monthly Subscription", ex);
}
}
}
//In your activity
ApplicationBillingClient appBillingClient =
ApplicationBillingClient.getInstance(applicationContext);
if (appBillingClient.isReady() == false)
{
appBillingClient.startConnection();
}
else
{
appBillingClient.getMonthlySubscription();
}
This was the application node, in the AndroidManifest, when the billing was breaking:
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:supportsRtl="true"
android:theme="#style/AppTheme"
tools:node="replace">
...
</application>
removing tools:node="replace" fixed the billing. Hopefully this will save someone the days I wasted.
My inbox has been flooded this morning by users getting license validation errors for one of my paid apps. The licensing on the app has worked fine for the past 5 years or so.
Unfortunately I've not been able to reproduce the issue...
It uses the old LVL from Google package="com.google.android.vending.licensing"
private class MyLicenseCheckerCallback implements LicenseCheckerCallback {
// Means: GooglePlay believes this user is legitimate
#Override
public void allow(int x, int policyReason, String y) {
if (isFinishing()) {
// Don't update UI if Activity is finishing.
return;
}
MainActivity.this.runOnUiThread(new Runnable() {
#Override
public void run() {
try { mProgressDialog.dismiss(); mProgressDialog = null; } catch (Exception e) {e.printStackTrace(); }
}
});
// Update server
Util.pingServer(getApplicationContext());
}
// Means: Google Play definitely thinks this version is a pirate version
#SuppressWarnings("SpellCheckingInspection")
public void dontAllow(int x, final int policyReason, String y) {
EventLog.i(TAG, "don't Allow: " + policyReason);
if (isFinishing()) {
// Don't update UI if Activity is finishing.
return;
}
MainActivity.this.runOnUiThread(new Runnable() {
#Override
public void run() {
try { mProgressDialog.dismiss(); mProgressDialog = null; } catch (Exception e) {e.printStackTrace(); }
showGoogleLicenseDialog(policyReason == Policy.RETRY ? 1 : 0);
}
});
}
// Means: Developer has not setup licensing properly
// ERROR_NOT_MARKET_MANAGED: not managed by Android Market (now called Google Play)
// More specifically, the version X of your application is not uploaded or published in Google Play
public void applicationError(final int errorCode) {
EventLog.e(TAG, "applicationError: " + errorCode);
if (isFinishing()) {
// Don't update UI if Activity is finishing.
return;
}
MainActivity.this.runOnUiThread(new Runnable() {
#Override
public void run() {
try { mProgressDialog.dismiss(); mProgressDialog = null; } catch (Exception e) {e.printStackTrace(); }
// Developer mistake dialog
String result = String.format(getString(R.string.application_error), errorCode);
ActivityHelper.showToast(MainActivity.this, "License problem: App Error: " + result, Toast.LENGTH_LONG);
}
});
}
}
private final MyLicenseCheckerCallback mMyLicenseCheckerCallback = new MyLicenseCheckerCallback();
It seems that Google have dorked this up in production. It can be fixed by updating to GooglePlay store 10.7.19
Latest Google Play Store 10.7.19 fixes LVL check
Another article here:
Google Play Store app licensing bug is putting developers in a horrible spot
A few Comments from users:
"Thanks, I side-loaded the playstore update and that seems to have fixed it."
"We gave up in the end and factory reset the phone. This seems to have fixed the issue..."
The main issue at the moment is that not all users have access to the 10.7.19 update...
UPDATE:
Also received several comments like:
"On the Settings tab, I toggled the Notification Access off/on. That seemed to wake it up. Errors stopped."
I'm using WiFi P2P for network service discovery, and I'm following the instructions as outlined on the developer guide. Here's the relevant code in my service class:
public void onCreate() {
manager = (WifiP2pManager) getSystemService(Context.WIFI_P2P_SERVICE);
channel = manager.initialize(this, getMainLooper(), null);
registerP2pService();
lookForServices();
}
private void registerP2pService() {
WifiP2pDnsSdServiceInfo serviceInfo =
WifiP2pDnsSdServiceInfo.newInstance("_service.name", "_presence._tcp", new HashMap<String, String>());
manager.addLocalService(channel, serviceInfo, new WifiP2pManager.ActionListener() {
#Override
public void onSuccess() {
Log.i("tag", "REGISTERED SERVICE");
}
#Override
public void onFailure(int arg0) {
Log.e("tag", "FAILED to register service");
}
});
}
private void setServiceListeners() {
WifiP2pDnsSdServiceRequest serviceRequest = WifiP2pDnsSdServiceRequest.newInstance();
manager.addServiceRequest(channel, serviceRequest,
new WifiP2pManager.ActionListener() {
#Override
public void onSuccess() {
Log.d("SCOPE", "Added a service request.");
discoverServices();
}
#Override
public void onFailure(int code) {
Log.e("tag", "Error adding service request.");
}
});
}
public void discoverServices() {
manager.discoverServices(channel, new WifiP2pManager.ActionListener() {
#Override
public void onSuccess() {
Log.d("tag", "Service discovery was initiated");
}
#Override
public void onFailure(int code) {
// This is where it keeps failing with error code 3 (NO_SERVICE_REQUESTS)
Log.d("SCOPE", "Service discovery failure code " + code);
}
});
}
The first time I run my service after rebooting the phone, service discovery is initiated just fine, but if I kill the service by stopping it from the app settings page, then open it again, it always fails with error code 3. If I reboot my phone and run the app again it works just fine. I am confused because I am explicitly calling discoverServices only when the service request has been successfully added.
My hunch is that it may be due to some code that is unrelated to service discovery because the service discovery code seems extremely straightforward, but if you see anything wrong with what I've posted, let me know. I'm grasping at straws here.
I'm running this on a Nexus 5 with Android 4.4.2.
I'm seeing this same problem on a second generation Nexus 7. It works fine the first time, subsequent attempts error out. Specifically, the addServiceRequest action listener reports success, but then discoverServices reports NO_SERVICE_REQUESTS.
(Teardown removeLocalService and removeServiceRequest succeed before exiting the app after the initial successful use.)
While it isn't an ideal answer, toggling wifi off then on again appears to reset whatever is stuck. That can be done programatically.
WifiDirect/NSD on Android has been a thorn in my side for the last couple of weeks.
I spent half of last week trying to figure out why my peer discovery calls would fail without any consistency with NO_SERVICE_REQUESTS and finally found a solution that works fairly well. It does seem to be a bug in the OS, and luckily the fine folks of P2Feed figured out a workaround:
if (code == WifiP2pManager.NO_SERVICE_REQUESTS) {
// initiate a stop on service discovery
manager.stopPeerDiscovery(channel, new WifiP2pManager.ActionListener() {
#Override
public void onSuccess() {
// initiate clearing of the all service requests
manager.clearServiceRequests(channel, new WifiP2pManager.ActionListener() {
#Override
public void onSuccess() {
// reset the service listeners, service requests, and discovery
setServiceListeners();
}
#Override
public void onFailure(int i) {
Log.d(TAG, "FAILED to clear service requests ");
}
});
}
#Override
public void onFailure(int i) {
Log.d(TAG, "FAILED to stop discovery");
}
});
}