Android: Switching from Admob SDK v6.4.1 to Google Play Services API library

Google announced on the 11th of February 2014 that they were deprecating the standalone Admob Android SDK. They will stop accepting apps using the old SDK on the 1st of August 2014. Ads will keep serving, but eventually you will have to switch over.

They've already started adding incompatibilities in the two projects. I first noticed this when I tried using both Play Services library for maps and Admob wasn't happy about it. I've documented the migration process along with a few other useful tips.

Things to remove

First of all, remove "libs/GoogleAdMobAdsSdk-6.4.1.jar". You won't be needing that anymore.

Things to add

Secondly, import the Google Play Services library project into Eclipse. You can find it at "Android-SDK/extras/google/google_play_services/libproject/google-play-services_lib".

Add it to your project as a library via right click (on project) > Properties > Android > Library > Add > google-play-services_lib.

In your AndroidManifest.xml file, add in this meta-data tag.

<meta-data android:name="com.google.android.gms.version" android:value="@integer/google_play_services_version"/>

While you're there:

<!-- Replace -->
<activity android:name="com.google.ads.AdActivity" android:configChanges="keyboard|keyboardHidden|orientation|screenLayout|uiMode|screenSize|smallestScreenSize"></activity>


<!-- with this -->
<activity android:name="com.google.android.gms.ads.AdActivity" android:configChanges="keyboard|keyboardHidden|orientation|screenLayout|uiMode|screenSize|smallestScreenSize"></activity>

Imports to change

Search through your imports and replace:

// Replace
import com.google.ads.AdRequest;
import com.google.ads.AdSize;
import com.google.ads.AdView;


// with this
import com.google.android.gms.ads.AdRequest;
import com.google.android.gms.ads.AdSize;
import com.google.android.gms.ads.AdView;

AdView code to change

You should have noticed the "The constructor AdRequest() is not visible" errors by now. If you're creating AdViews from code then you'll have to tweak it a little.

// Replace
AdView ad = new AdView(this, AdSize.BANNER, YOUR_ADMOB_ID);
ad.loadAd(new AdRequest());


// with this
ad = new AdView(this);
ad.setAdSize(AdSize.BANNER);
ad.setAdUnitId(YOUR_ADMOB_ID);

AdRequest adRequest = new AdRequest.Builder().build();
ad.loadAd(adRequest);

Remember to manage configuration changes on pause/resume.

@Override
protected void onPause() {
if (ad != null) {
ad.pause();
}
super.onPause();
}

@Override
protected void onResume() {
if (ad != null) {
ad.resume();
}
super.onResume();
}

@Override
public void onDestroy() {
if (ad != null) {
ad.destroy();
}
super.onDestroy();
}

Done!

Check out the Google migration guide if you're also using AdListener interfaces or if anything in this post was confusing.

Other than that, your project should be good to go!

av0A06E_460sa
See any other problems? LASER BEAM THEM!

Sources

Android: Switching your app project from ActionBarSherlock to ActionBar in app compatibility library

The author of ActionBarSherlock Jake Wharton is no longer working on the library. Why? Because Google has released their version of his library and it works in (mostly) the same way.

There's no real reason to keep using ABS other than if you've abandoned your project or there is absolutely zero budget allocated to it. Even Wharton has recommended using the AppCompat library as it's ALMOST a complete drop-in replacement.

I'll run through a checklist of things you'll need to do in order to switch over your ActionBarSherlock based project to a AppCompat based project.

Switching over

First of all, close ActionBarSherlock in Eclipse. This will ensure your project will raise every error known to man, but it'll give you a starting point.

Now import an existing project from the SDK by right clicking on the Package Explorer > Import > General > Existing Projects into Workspace.

Now navigate to "AndroidSDK\extras\android\support\v7\appcompat" and select a project called "android-support-v7-appcompat".

Make sure "Copy projects into workspace" is UNTICKED. This makes it easier to upgrade the library via the SDK manager when updates are released.

Click Finish to import.

image image

Now right click on your app project > Properties > Android > Select ActionBarSherlock from the list of libraries and remove it. Add in "android-support-v7-appcompat".

While you still have the project properties open, add AppCompat to your build path by Java Build Path > Projects > Add > "android-support-v7-appcompat".

Android.xml

A few small changes are required here. Good thing is the minimum API level is still 7 for both ABS and AppCompat.

First up, the application theme. Change the following

<!-- before -->
<application android:theme="@style/Theme.Sherlock">

<!-- after -->
<application android:theme="@style/Theme.AppCompat">

This applies for all variances such as Theme.Sherlock.Light and Theme.Sherlock.Light.DarkActionBar, replace them with Theme.AppCompat.Light and Theme.AppCompat.Light.DarkActionBar respectively.

image
If in doubt, you can always autocomplete it.

Changing out SherlockActivity and SherlockFragmentActivity

We used to treat activities and fragment activities differently by inheriting them from different base classes. At least we can do away with that now by just using ActionBarActivity (from android.support.v7.app).

// Before
public class MainActivity extends SherlockFragmentActivity {

// After
public class MainActivity extends ActionBarActivity {

Rinse and repeat for all activities extending either SherlockActivity or SherlockFragmentActivity.

SherlockFragment to AppCompat Fragments

image

Similarly with SherlockFragment, simply search and replace them with the Fragment class. After saving, press Ctrl+Shift+O to fix up your imports.

image 
Be sure to use the Fragment from the support library.

// Before
import com.actionbarsherlock.app.SherlockFragment;
public class SurfaceViewFragment extends SherlockFragment {

// After
import android.support.v4.app.Fragment;
public class SurfaceViewFragment extends Fragment {

Again, if you're supporting API levels less than 11 then make sure you're importing from the compatibility library (android.support.v4.app) rather than API library.

Fixing up Menus

image

A quick search & replace can be done on getSupportMenuInflater() by replacing it with getMenuInflater().

If you're supporting any API levels below 11, a not-so-easy fix would be MenuItem.setShowAsAction(). In order to fix this, you'll need to use MenuItemCompat.setShowAsAction().

I don't have any magic solutions here, sorry.

// Before
menuItem.setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS);

// After
MenuItemCompat.setShowAsAction(menu.getItem(i -1), MenuItemCompat.SHOW_AS_ACTION_ALWAYS);

I'm guessing it had to be done like that because the API level requirements were already set. Kinda sucks because it leads to slightly messier code though.

"Menu cannot be resolved to a type" is always a fun one. Simply open the file where that error is found and press Ctrl+Shift+O. If this doesn't work, make sure you've switched the activity over to ActionBarActivity.

That's all folks!

This may look like a long write-up, but I've added images and snippets to make it super clear. The process is pretty simple and repetitive so there's no real problems to run into.

The two libraries are mostly compatible and there's only minor changes required. The process of following the little red crosses took less than 5 minutes, but may take longer for projects which have many more activities/fragments.

9RRH5Tm
Almost as easy as translating Obama's speech into sign language.

Android: Widgets and multiple PendingIntent calls

It's been a while since I've blogged this, but I had an issue with PendingIntent when implementing widgets for Code Peeker Pro.

tldr version; The documentation doesn't make this clear, but when you're calling PendingIntent.getActivity(), the damn requestCode matters!

The widgets in Code Peeker allow you to create shortcuts to files on your phone. Each widget can point to a single file, which you choose upon creation of widget.

When initialising the widget, I set up PendingIntent on the view so it opens the appropriate file when tapped. In the majority of solutions on StackOverflow, I've seen "requestCode" be set to 0.

PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
// ...
views.setOnClickPendingIntent(R.id.widget_layout, pendingIntent);
appWidgetManager.updateAppWidget(widgetId, views);

Now that's fine and dandy, until you have multiple widgets. Say for instance I have widget 1 which opens up file A, and widget 2 which opens up file B. Simple enough right?

NOPE! In my test cases, all widgets will open the same file, the most recently added one. In this case, both widgets 1 and 2 will only open file B. The PendingIntent is seemlingly shared across the widget views. Even after scouring the documentation, the notes for PendingIntent.getActivity() don't really raise any issues here either.

Only until I changed requestCode from "0" to the widget ID does this work properly. To infuriate me even further, the documentation previous said "currently not used" when describing the requestCode!!!

The new fix is just one arg change, "widgetID" in place of 0 for requestCode.

PendingIntent pendingIntent = PendingIntent.getActivity(context, widgetId, intent, PendingIntent.FLAG_UPDATE_CURRENT);

tumblr_m3htpr2VBt1rqbr1po1_500
Google, Batman ain't got time for your bad docs!

Sources

The Day We Fight Back

Whoops, almost forgot to add the blackout banner!
https://thedaywefightback.org/international/
Today, February 11th, 2014 is The Day We Fight Back against mass surveillance.
 
Copyright © Twig's Tech Tips
Theme by BloggerThemes & TopWPThemes Sponsored by iBlogtoBlog