I wanted to create an Overlay, like a HUD, that resides on the screen during my applications activity stack (the task of my app) changes.
I found a couple of examples u
You really only have two options.
1) You can create an activity with the theme of Theme.Dialog. This will display a popup on top of your window. You can create the dialog to be modal-less (can click through). In my quick testing I wasn't able to get overlay to the edges of my screen although maybe modifying the theme would fix that.
MainActivity.java
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button test = (Button) this.findViewById(R.id.test);
test.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
((Button) v).setBackgroundColor(Color.RED);
}
});
Intent i = new Intent(this, SecondActivity.class);
startActivity(i);
}
}
SecondActivity.java
public class SecondActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.second_main);
Window window = getWindow();
window.setFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE, WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE);
window.clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND);
window.setLayout(WindowManager.LayoutParams.MATCH_PARENT, WindowManager.LayoutParams.MATCH_PARENT);
window.setGravity(Gravity.BOTTOM);
}
@Override
public void onBackPressed() {
//Override to prevent back button from closing the second activity dialog
}
}
Manifest
....
<activity
android:name="com.example.control.MainActivity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name="com.example.control.SecondActivity"
android:theme="@android:style/Theme.Dialog"
android:label="@string/app_name" >
....
</activity>
....
2) The second option is to use a SYSTEM_ALERT_WINDOW. I prefer this method significantly more. You are correct that it CAN be visible and on top of every other app, however, you can control when it is visible and when it isn't. I'm not going to post any source code but I will give you a general plan of attack.
When you create the service, bind to it using an AIDL. This way you'll be able to talk directly with the service to tell it when to 'hide' and 'show' the overlay. Speaking of hiding and showing, onPause and onResume can be used to tell the service to hide and show the overlay. Lastly, if you need to receive click events on your overlay, that will prove to be tricky as the touch events don't always act the way you expect them to.
Good Luck.
I think the following will be of interest to you. You won't require android.permission.SYSTEM_ALERT_WINDOW
. The code is for the Application class.
Comments should help you understand the logic. The code should work right out of the box.
public class YourApplication extends Application {
// Popup to show persistent view
PopupWindow pw;
// View held by Popup
LinearLayout ll;
@Override
public void onCreate() {
super.onCreate();
// Register for Activity Lifecyle Callbacks
registerActivityLifecycleCallbacks(new YourCallBack());
// Initialize the view
ll = new LinearLayout(this);
ll.setLayoutParams(new LayoutParams(100, 100));
ll.setBackgroundColor(Color.BLUE);
// Initialize popup
pw = new PopupWindow(ll, 100, 100);
// Set popup's window layout type to TYPE_TOAST
Method[] methods = PopupWindow.class.getMethods();
for(Method m: methods){
if(m.getName().equals("setWindowLayoutType")) {
try{
m.invoke(pw, WindowManager.LayoutParams.TYPE_TOAST);
}catch(Exception e){
e.printStackTrace();
}
break;
}
}
}
@Override
public void onTerminate() {
super.onTerminate();
if (pw != null && pw.isShowing()) {
pw.dismiss();
}
};
private final class YourCallBack implements ActivityLifecycleCallbacks {
int numOfRunning = 0;
@Override
public void onActivityCreated(Activity arg0, Bundle arg1) { }
@Override
public void onActivityDestroyed(Activity arg0) { }
@Override
public void onActivityPaused(Activity arg0) {
// An activity has been paused
// Decrement count, but wait for a certain
// period of time, in case another activity
// from this application is being launched
numOfRunning--;
// Delay: 100 ms
// If no activity's onResumed() was called,
// its safe to assume that the application
// has been paused, in which case, dismiss
// the popup
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
if (numOfRunning == 0) {
pw.dismiss();
}
}
}, 100L);
}
@Override
public void onActivityResumed(Activity arg0) {
// If no activities were running, show the popup
if (numOfRunning == 0) {
pw.showAtLocation(ll, Gravity.BOTTOM, 0, 0);
}
// Now, one activity is running
numOfRunning++;
}
@Override
public void onActivitySaveInstanceState(Activity arg0, Bundle arg1) { }
@Override
public void onActivityStarted(Activity arg0) { }
@Override
public void onActivityStopped(Activity arg0) { }
};
}