Ad Mixer (II) – How to mix Quattro Wireless Ads, AdMob Ads, and your own clickable Ads

What an impressive long blog title!
Quattro Wireless Ads has slightly better eCPM than AdMob, and it allows your to put a default image Ads (not clickable). However, its fillrate is unbearably low (50% ~ 90%, typically around 75%, according to my 2 week test). Here, I’m showing you a way to mix Ads from Quattro Wireless, AdMob, and your own Ads.
For information about how to setup Ads on android apps using Quattro Wirelss, click here.
Step 1: Prepare your own banner ads.
Setp 2: Add the following Ads banner in your layout xml:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

<FrameLayout android:layout_width="fill_parent"
android:layout_height="50dp" android:gravity="top">
 
<ImageView android:id="@+id/ownads" android:src="@drawable/banner_ad"
android:layout_width="wrap_content" android:layout_height="wrap_content" />
 
<com.admob.android.ads.AdView
android:id="@+id/adMob" android:layout_width="fill_parent"
android:layout_alignParentTop="true" android:layout_marginTop="10dp"
android:layout_height="fill_parent" />
 
<com.qwapi.adclient.android.view.QWAdView
android:id="@+id/QWAd" android:layout_width="fill_parent"
android:layout_height="fill_parent" qwad:siteId="xyz"
qwad:publisherId="xyz" qwad:mediaType="banner,text"
qwad:displayMode="autoRotate" qwad:placement="top"
qwad:animation="fade" />
</FrameLayout>

Step 3: Implement Quattro’s AdEventsListener …

Ad Mixer (I) – How to mix AdMob Ads and your own clickable Ads

If you are an AdMob publisher, you will know how fluctuating their fillrates are: mine varies from 40% to 100%. What’s even worse is that they don’t support default Ads. So I decide to mix in mine:
For information about how to setup Ads on android apps using AdMob, click here.
Step 1: Prepare your own banner ads (320×50 or 480×50. Note AdMob’s ads has a fixed height of 50 pixels).
Step 2: Replace your AdView with the following framelayout in your layout xml:

1
2
3
4
5
6
7
8
9
10
11
12

<FrameLayout android:layout_width="fill_parent"
android:layout_height="wrap_content" android:gravity="center_horizontal">
 
<ImageView android:id="@+id/ownads" android:src="@drawable/banner_ad"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
 
<com.admob.android.ads.AdView android:id="@+id/ad"
android:layout_width="fill_parent" android:layout_height="50dp"
android:layout_alignParentBottom="true"
app:backgroundColor="#000000" app:textColor="#FFFFFF" />
</FrameLayout>

Step 3: Change your activity to include this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27

private static final Uri SAME2D_URI =
Uri.parse("market://search?q=pname:com.clingmarks.same2dfree");
 
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) …

Make Your Android Phone Vibrate

So I got this good suggestion from one user’s comment: when shake to shuffle, make the phone vibrate.
It’s actually a very simple 2-step operation, but android developer site wasn’t very clear about. Here’s how I did it:

Add permission in AndroidManifest.xml file like this:

<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<uses-permission android:name="android.permission.VIBRATE" />
……
</manifest>

In your program when you want the phone to vibrate:

// vibration lasts 300 milliseconds
((Vibrator)getSystemService(VIBRATOR_SERVICE)).vibrate(300);

Done!

How to detect shake motion on Android phone

When I was implementing the shake-to-shuffle feature in Pair-Up game, I googled for a similar code-snippet but didn’t have much luck. Eventually I came across this hidden code in Android Developer Guide which talks about using the phone motion sensor to program:
http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/os/Sensors.html
Alas! It can be done! But I just need a very simple function to detect if there’s a shake action. So my actual code is a lot simpler:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62

// Need to implement SensorListener
public class ShakeActivity extends Activity implements SensorListener {
// For shake motion detection.
private SensorManager sensorMgr;
private long lastUpdate = -1;
private float x, y, z;
private float last_x, last_y, last_z;
private static final int SHAKE_THRESHOLD = 800;
 
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
…… // other initializations
// start motion …

A Bug Found by Fast Fingers

OK, so there IS a bug in this game.
Comment posted by Tony this morning:
Fun, managed to end up with two tiles that didn’t match though….
The moment I read this, I immediately know what went wrong: he’s typing too fast! (well, not his fault though). Here’s more details: when you tapped on two identical tiles, the system spent 0.3 seconds drawing a connecting path between them. Now if you have a fast finger, you can break it within that 0.3 seconds.
The bullet-proof solution to this would be freezing the board while drawing the path. But this introduced some computation overhead. Instead, I simply reduce the drawing time from 0.3 second to 0.01, and still able to see the flash of a connecting line on screen. Bingo! The bug fix was launched!

JVM Wrong Timezone Bug

A few weeks ago we noticed that one of our applications had wrong timestamps in the log files by late for an hour.
At first I thought the timezone setting in the OS could be wrong but our ops people confirmed it is actually correct. Then I thought the JVM settings on that server must have something wrong. But I compared the JVM directories on the problematic server to a good server, they are exactly the same. This puzzles me. Then I wrote a simple Java app to print out all system properties and found that on the “bad” server, the default timezone is “GMT-08:00″ instead of “US/Pacific”.
After searching online, it turned out this is actually a bug in Java.
In short, in some cases JVM can get a wrong timezone from the machine, even if all the settings are right. What happened is when JVM starts, it looks for a matched …