I’m currently trying to write an app for one special device running Android 2.3.4, that places a system overlay on a precisely defined spot on the screen. This is why I am positioning the layer using absolute values.
I wrote an activity (including two buttons in the layout) that starts and stops a service displaying this overlay.
public class MyActivity extends Activity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
public void showOverlay(View view) {
Intent i = new Intent("myPackage.myService");
startService(i);
}
public void hideOverlay(View view) {
Intent i = new Intent("myPackage.myService");
stopService(i);
}
}
And this is my service (which was also added to the manifest file).
public class MyService extends Service {
ImageView iv;
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public void onCreate() {
super.onCreate();
int imageRes = 0;
final WindowManager.LayoutParams params = new WindowManager.LayoutParams(
WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY,
WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN,
PixelFormat.TRANSLUCENT);
params.gravity = Gravity.NO_GRAVITY;
params.alpha = 1;
switch (findRotation()) {
case Surface.ROTATION_0:
params.height = 12; params.width = 600; params.x = 0; params.y = 1012;
imageRes = R.drawable.horizontal;
break;
case Surface.ROTATION_180:
params.height = 12; params.width = 600; params.x = 0; params.y = 0;
imageRes = R.drawable.horizontal;
break;
case Surface.ROTATION_90:
params.height = 600; params.width = 12; params.x = 1012; params.y = 0;
imageRes = R.drawable.vertical;
break;
case Surface.ROTATION_270:
params.height = 600; params.width = 12; params.x = 0; params.y = 0;
imageRes = R.drawable.vertical;
break;
}
final WindowManager wm = (WindowManager) getSystemService(WINDOW_SERVICE);
iv = new ImageView(getApplicationContext());
iv.setClickable(false);
iv.setImageResource(imageRes);
iv.draw(new android.graphics.Canvas());
wm.addView(iv, params);
}
private int findRotation() {
Display display = ((WindowManager) getSystemService(WINDOW_SERVICE)).getDefaultDisplay();
return display.getRotation();
}
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
onDestroy(); //I don't know how to to make the service reposition the layer, so I used this. Not nice but it works
onCreate();
}
@Override
public void onDestroy() {
super.onDestroy();
if(iv != null) {
((WindowManager) getSystemService(WINDOW_SERVICE)).removeView(iv);
iv = null;
}
}
}
The image to display as overlay has the width (or heigth, I didn’t find a method to rotate drawabled at API level 10, so I used two images, one for horizontal display, one for vertical) of my device’s screen resolution in portrait mode (=600) and a heigth (or width) of 12 pixels. I want it to be positioned where the hardware buttons are, i.e. in portrait mode on the bottom, when turned 90° counter-clockwise on the right, when turned 180° on the top and so on.
This works well for a rotation of 0° and 90° (ccw), but for the other two orientations the image is displayed in the middle of the screen instead of at the top or on the left. What am I doing wrong?
EDIT 2012-04-19:
I have changed the value of params.y for ROTATION_180 to -1012, and this case works now. I don’t think this is expected behaviour, though. A similar change for ROTATION_270 did not work…
OK, I’m sorry, I made a mistake when changing the parameters for ROTATION_270, when I wrote my edit.
I got the code to do what I wanted, here’s what I did:
I changed the y-param for 180° to -1012 and the x-param for 270° to -1012, too. Now, in all four orientations the image is displayed where the hardware buttons are.
I write it down here just for the sake of completeness.
(…)
(…)