I got ads limit on my Account 1, so I want to use another admob account in my app. The hard part is that I want to use both accounts and I switch between accounts using remote config. That includes changing APP ID in AndroidManifest.xml and replacing ad unit IDs in my activity. Is it theoretically/practically possible? If yes, how can I do that? What's admob's policy regarding this.
I tried changing app ID using this:
`// Retrieve the boolean remote config parameter from Firebase Remote Config
Boolean useAdmobAppId1 = FirebaseRemoteConfig.getInstance().getBoolean("use_admob_app_id_1");
// Determine which Admob App ID to use based on the value of the remote config parameter
String admobAppId;
if (useAdmobAppId1) {
admobAppId = "ca-app-pub-496948190xxxxxxx~3460231xxx";
} else {
admobAppId = "ca-app-pub-659546309xxxxxxx~6818220xxx";
}
// Update the AndroidManifest.xml file with the determined Admob App ID
try {
ApplicationInfo ai = getPackageManager().getApplicationInfo(getPackageName(), PackageManager.GET_META_DATA);
Bundle bundle = ai.metaData;
bundle.putString("com.google.android.gms.ads.APPLICATION_ID", admobAppId);
} catch (PackageManager.NameNotFoundException e) {
Log.e("AdmobAppIdUpdater", "Failed to update Admob App ID in AndroidManifest.xml", e);
}
and also tried doing this:
#Override
public void onInitializationComplete(InitializationStatus initializationStatus) {
updateAdUnitIds();
}
});
private void updateAdUnitIds() {
if (FirebaseRemoteConfig.getInstance().getBoolean("use_admob_account_1")) {
AD_UNIT_ID = getString(R.string.admob_account_1_rewarded_video_ad_unit_id);
REW_INT_AD_UNIT_ID = getString(R.string.admob_account_1_rewarded_int_ad_unit_id);
} else {
AD_UNIT_ID = getString(R.string.admob_account_2_rewarded_video_ad_unit_id);
REW_INT_AD_UNIT_ID = getString(R.string.admob_account_2_rewarded_int_ad_unit_id);
}}```
Related
I want to use Youtube API to get the subscription list of a user. It requires oauth.
I read that implementing google sign in will make it easier to access this API
I followed Google's documentation and now I got the signing in working
I have these files now.
My question:
1) Which sample do I need to use, IdTokenActivity.java or RestApiActivity.java
2) How can I use the sample code to access Youtube API? It doesn't say and the documentation is confusing
Which sample do I need to use, IdTokenActivity.java or RestApiActivity.java ?
IdTokenActivity.java aims at retrieving an id_token. The id_token is a JWT token designed to be sent to a backend to authenticate the user as a real (trusted) Google user. You can find more information about the flow for the backend here.
RestApiActivity.java is used to consume Google API which is what you are trying to do.
How can I use the sample code to access Youtube API?
Here are the steps :
Go to Google Signin setup for Android, download google-services.json and place it in your app folder
in google developer console enable Youtube Data API
add the following to app build.gradle :
compile 'com.google.android.gms:play-services-auth:10.0.1'
compile 'com.google.api-client:google-api-client-android:1.22.0' exclude module: 'httpclient'
compile 'com.google.apis:google-api-services-youtube:v3-rev182-1.22.0'
with apply plugin: 'com.google.gms.google-services' to the bottom of your file
update the following to your top level build.gradle :
dependencies {
classpath 'com.google.gms:google-services:3.0.0'
}
Include the RestApiActivity.java in your project and update the following :
// Scope for reading user's contacts
private static final String YOUTUBE_SCOPE = "https://www.googleapis.com/auth/youtube";
...
// Configure sign-in to request the user's ID, email address, basic profile,
// and readonly access to contacts.
GoogleSignInOptions gso = new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
.requestScopes(new Scope(YOUTUBE_SCOPE))
.requestEmail()
.build();
and when the client is authenticated (in handleSignInResult) , request the subscription list as following :
/**
* AsyncTask that uses the credentials from Google Sign In to access Youtube subscription API.
*/
private class GetSubscriptionTask extends AsyncTask<Account, Void, List<Subscription>> {
#Override
protected void onPreExecute() {
showProgressDialog();
}
#Override
protected List<Subscription> doInBackground(Account... params) {
try {
GoogleAccountCredential credential = GoogleAccountCredential.usingOAuth2(
RestApiActivity.this,
Collections.singleton(YOUTUBE_SCOPE));
credential.setSelectedAccount(params[0]);
YouTube youtube = new YouTube.Builder(HTTP_TRANSPORT, JSON_FACTORY, credential)
.setApplicationName("Google Sign In Quickstart")
.build();
SubscriptionListResponse connectionsResponse = youtube
.subscriptions()
.list("snippet")
.setChannelId("UCfyuWgCPu5WneQwuLBWd7Pg")
.execute();
return connectionsResponse.getItems();
} catch (UserRecoverableAuthIOException userRecoverableException) {
Log.w(TAG, "getSubscription:recoverable exception", userRecoverableException);
startActivityForResult(userRecoverableException.getIntent(), RC_RECOVERABLE);
} catch (IOException e) {
Log.w(TAG, "getSubscription:exception", e);
}
return null;
}
#Override
protected void onPostExecute(List<Subscription> subscriptions) {
hideProgressDialog();
if (subscriptions != null) {
Log.d(TAG, "subscriptions : size=" + subscriptions.size());
// Get names of all connections
for (int i = 0; i < subscriptions.size(); i++) {
Log.v(TAG, "subscription : " + subscriptions.get(i).getId());
}
} else {
Log.d(TAG, "subscriptions: null");
mDetailTextView.setText("None");
}
}
}
which is launched in lieu of GetContacts with :
new GetSubscriptionTask().execute(mAccount);
You can find a complete example here
I am trying to check if my if my mobile device is dual sim, if sim1 is ready, if sim2 is ready, I am done with this using java reflection, now i want to find out if sim1 isRoaming and if sim2 isRoaming, and if its dual sim which sim is set as default. Is it possible with the help of java reflection.
You can do something like this:
public int getDefaultSimmm(Context context) {
Object tm = context.getSystemService(Context.TELEPHONY_SERVICE);
Method method_getDefaultSim;
int defaultSimm = -1;
try {
method_getDefaultSim = tm.getClass().getDeclaredMethod("getDefaultSim");
method_getDefaultSim.setAccessible(true);
defaultSimm = (Integer) method_getDefaultSim.invoke(tm);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Method method_getSmsDefaultSim;
int smsDefaultSim = -1;
try {
method_getSmsDefaultSim = tm.getClass().getDeclaredMethod("getSmsDefaultSim");
smsDefaultSim = (Integer) method_getSmsDefaultSim.invoke(tm);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return smsDefaultSim;
}
Starting from API 22 (Lollipop MR1) android has officially added SubscriptionManager class which gives all the information required by the developer in relation to sim cards and related services.
Documentation for SubscriptionManager
However support for retrieving defaults for calls, SMS and Mobile data were added in API 24.
If you use your minimum SDK version to 24 you can use getDefaultSmsSubscriptionId() method to get SMS default set by the user
SubscriptionManager manager = context.getSystemService(Context.TELEPHONY_SUBSCRIPTION_SERVICE);
int defaultSmsId = manager.getDefaultSmsSubscriptionId();
SubscriptionInfo info = manager.getActiveSubscriptionInfo(defaultSmsId);
Note: Above mention call requires READ_PHONE_STATE permission. Make sure you add it in your manifest file
A very late answer but I got into developing an application which has the above requirement
Below is the latest way to get it done.
/**
* #return - True - if any sim selected as default sim , False - No default sim is selected or
* permission for reading the sim status is not enabled
*/
boolean isDefaultSimSetForCall() {
if (ContextCompat.checkSelfPermission(context, Manifest.permission.READ_PHONE_STATE) != PackageManager.PERMISSION_GRANTED) {
Log.d(Utils.getTag(), "Read Phone state permission Disabled");
genericCallbacks.onPermissionAccessError(Constants.PermissionErrorCodes.READ_PHONE_STATE_ACCESS);
return false;
} else {
PhoneAccountHandle defaultPhoneAccount = telecomManager.getDefaultOutgoingPhoneAccount(Uri.fromParts("tel", "text", null).getScheme());
if (defaultPhoneAccount != null) {
Log.d(Utils.getTag(), "DefaultOutgoingPhoneAccount: " + defaultPhoneAccount.getId());
return true;
}
}
return false;
}
From the received PhoneAccountHandle, we can get the necessary fields
I'm implementing in-App purchase in an Android App. I set up the App in the Google Play Developer Console and setup several products.
I added IabHelper and the associated billing files to my codebase per the Android docs. I'm able to successfully setup:
String base64EncodedPublicKey = Configurations.getInstance().getGooglePlayLicenseKey();
googlePlayHelper = new IabHelper(AtavistApplication.getContext(), base64EncodedPublicKey);
googlePlayHelper.startSetup(new IabHelper.OnIabSetupFinishedListener() {
public void onIabSetupFinished(IabResult result) {
if (!result.isSuccess()) {
Utilities.log("Unable to setup billing: " + result);
isBillingSetup = false;
} else {
Utilities.log("Billing setup successfully");
isBillingSetup = true;
}
}
});
But when I query Google Play for product information like so:
IabHelper.QueryInventoryFinishedListener mQueryFinishedListener = new IabHelper.QueryInventoryFinishedListener() {
public void onQueryInventoryFinished(IabResult result, Inventory inventory)
{
if (result.isFailure()) {
Utilities.log("getProducts failed");
callback.failure(null);
} else {
Utilities.log("getProducts succeeded");
callback.success(inventory);
}
}
};
googlePlayHelper.queryInventoryAsync(true, identifiers, mQueryFinishedListener);
Where identifiers is a list of String product identifiers:
ArrayList<String> productIDs = new ArrayList<String>();
productIDs.add("com.first.product");
productIDs.add("com.second.product");
productIDs.add("com.third.product");
I get a successful response that contains only one product that isn't a product that's setup in my Google Play account. Its productID is the productID of a product that we have offered before but it was deleted from the Google Play list of active products a while ago.
Questions:
Why is queryInventoryAsync not returning the proper list?
Why on earth would it return a product that's not currently set up in Google Play?
Am I missing some basic configuration step that's causing this confusion?
It turns out that there was some dissonance between the apk that I had uploaded to the Google Play Developer Console (before setting up the products) and the codebase/apk that I was building and testing with.
Specifically, the bundle identifier (package name) was different, and they were signed with different keystores.
No idea why this would return a seemingly valid product rather than an explicit error, but bringing the two apks in line resolved the issue.
I did a mistake that apparently can be solved only by uninstalling and then installing my app again.
I delivered a message to the users, but no-one seems to uninstall it.
AFAIK, if I change the certificate file, the play store won't let me upload the application, and
obviously I don't want to upload a new app.
Is there a way to force uninstall in order to update?
Thanks!
There's no killswitch to remotely force uninstalls (that'd be a security nightmare). What you can do is publish a fixed version on Google Play, and wait for users to upgrade.
I don't know if this can help you but i had the same problem. The solution for me is that i check the app version every time the user opens it and compare it with a version code stored on apache server (in a checkversion.php file).
If versions doesn't match, i show a not cancelable dialog that ask the user to go to market and download the update.
Here is an example (keep in mind that i use Volley library to handle connections):
public class UpdateManager {
private Activity ac;
private HashMap<String,String> params;
public UpdateManager(Activity ac) {
this.ac = ac;
}
public void checkForUpdates() {
Log.d("UpdateManager","checkForUpdates() - Started...");
params = new HashMap<String,String>();
params.put("request","checkforupdates");
try {
params.put("versioncode", String.valueOf(ac.getPackageManager().getPackageInfo(ac.getPackageName(), 0).versionCode));
} catch (NameNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if (Helper.isInternetAvailable(ac)) { //this is a class i made to check internet connection availability
checkAppVersion();
} else { Log.d("UpdateManager","CheckForUpdates(): Impossible to update version due to lack of connection"); }
}
private void checkAppVersion() {
Log.d("UpdateManager","checkAppVersion() - Request started...");
JsonObjectRequest req = new JsonObjectRequest("http://yourserver/checkappversion.php", new JSONObject(params),
new Response.Listener<JSONObject>() {
#Override
public void onResponse(JSONObject response) {
if (response != null && response.has("result")) {
try {
Log.d("UpdateManager","checkAppVersion() - Request finished - Response: "+response.getString("result"));
if (response.getString("result").matches("updaterequested")) { //Update requested. Show the relative dialog
Log.d("UpdateManager","Update requested");
askUserForUpdate();
}
else if (response.getString("result").matches("current")) { //Same version. Do nothing
Log.d("UpdateManager","Version is up to date");
}
else if (response.getString("result").matches("error")) { //You can return an error message if error occurred on server
Log.d("UpdateManager","checkappversion Error - "+response.getString("error"));
}
VolleyLog.v("Response:%n %s", response.toString(4));
} catch (JSONException e) {
e.printStackTrace();
}
}
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
Log.e("UpdateManager","Volley Error - "+error.getMessage());
}
});
req.setRetryPolicy(new DefaultRetryPolicy(60000,0,DefaultRetryPolicy.DEFAULT_BACKOFF_MULT));
ConnectionController.getInstance().addToRequestQueue(req);
}
public void askUserForUpdate() {
final Dialog diag = new Dialog(ac);
diag.requestWindowFeature(Window.FEATURE_NO_TITLE);
diag.setContentView(R.layout.updatemanager_requestupdate_dialog);
diag.setCancelable(false);
diag.getWindow().setBackgroundDrawable(new ColorDrawable(android.graphics.Color.TRANSPARENT));
TextView t = (TextView)diag.findViewById(R.id.requestupdate_dialog_main_text);
ImageView im_ok = (ImageView)diag.findViewById(R.id.requestupdate_dialog_ok);
ImageView im_canc = (ImageView)diag.findViewById(R.id.requestupdate_dialog_canc);
t.setText(ac.getResources().getString(R.string.update_manager_askuserforupdate));
im_canc.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
diag.dismiss();
ac.finish();
}
});
im_ok.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setData(Uri.parse("market://details?id="+ac.getPackageName()));
diag.dismiss();
ac.startActivity(intent);
ac.finish();
}
});
diag.show();
}
}
You can then use it when your main activity (or maybe login activity) starts like this:
UpdateManager updateManager = new UpdateManager(MainActivity.this); //i assume MainActicity as the calling activity
updateManager.checkForUpdates();
Obviously this has to be implemented into the application code so, the first time, you have to rely only on the user to manually upgrade it. But this can help if you have the same problem in the future.
This is an extract from my personal code so you have to rearrange it to your needings. Hope this helps someone.
Users should be able to go to Settings > Applications > Manage Applications and select the application to be removed. I've never seen a case where the application can't be removed this way, except in the case of built-in applications which require a rooted device to remove.
There is an icon displayed in account settings for each account. For Google account there is one icon, for Facebook another.
Is there a way of getting this icon from the code in application?
Finally, I solved it:
private Drawable getIconForAccount(Account account, AccountManager manager) {
AuthenticatorDescription[] descriptions = manager.getAuthenticatorTypes();
PackageManager pm = getContext().getPackageManager();
for (AuthenticatorDescription description: descriptions) {
if (description.type.equals(account.type)) {
return pm.getDrawable(description.packageName, description.iconId, null);
}
}
return null;
}