5

I need to have a floating view over all of my application.
I can use Window_service but I don't need my view to be outside of the app.
Only inside my app.

I also don't want the user to see "draw on other app" permission.
How else can I do it?

Phantômaxx
  • 37,901
  • 21
  • 84
  • 115
roiberg
  • 13,629
  • 12
  • 60
  • 91
  • 2
    You can build your application inside an Activity that have your floating view and fragments, so when you need to change the "background" content you will just alter the fragment... – GhostDerfel Jan 30 '14 at 19:27

1 Answers1

0

I've had to do something similar to this. In my case, I wanted all of my logging statements to be shown above the whole application (Similar to the Developer Options -> Show CPU Usage settings in an Android device).

In my case, I just wanted to display a TextView on top of the app, but you can pretty much replace it with your own layout.

Here's an example of the code I used:

import android.app.Service;
import android.content.Intent;
import android.graphics.Color;
import android.graphics.PixelFormat;
import android.os.Binder;
import android.os.IBinder;
import android.text.Spannable;
import android.text.SpannableString;
import android.text.style.BackgroundColorSpan;
import android.view.WindowManager;
import android.widget.TextView;

public class OverlayService extends Service {

    private final IBinder mBinder = new LocalBinder();
    private TextView mTextView;
    private Spannable mSpannable;

    public class LocalBinder extends Binder {
        public OverlayService getService() {
            return OverlayService.this;
        }
    }

    @Override
    public IBinder onBind(Intent intent) {
        return mBinder;
    }

    @Override
    public void onCreate() {
        super.onCreate();

        mTextView = new TextView(this);
        mTextView.setTextSize(10);
        mTextView.setTextColor(Color.WHITE);

        WindowManager.LayoutParams params = new WindowManager.LayoutParams(WindowManager.LayoutParams.MATCH_PARENT, WindowManager.LayoutParams.MATCH_PARENT,
                WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY, 0 | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE, PixelFormat.TRANSLUCENT);
        WindowManager wm = (WindowManager) getSystemService(WINDOW_SERVICE);
        wm.addView(mTextView, params);
    }

    public void setText(String text) {

        mSpannable = new SpannableString(text);
        mSpannable.setSpan(new BackgroundColorSpan(0xD993d2b9),0, text.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);           

        // simple logic to only display 10 lines
        if(mTextView.getLineCount() > 10) {
            mTextView.setText(mSpannable);
        } else {
            mTextView.append(mSpannable);
        }
        mTextView.append("\n");

    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        if (mTextView != null) {
            WindowManager wm = (WindowManager) getSystemService(WINDOW_SERVICE);
            wm.removeView(mTextView);
        }
    }
}

Then you can just connect with this Service from your Activity and set it's text, like so:

ServiceConnection mConnection = new ServiceConnection() {

                        @Override
                        public void onServiceConnected(ComponentName className, IBinder service) {
                                LocalBinder binder = (LocalBinder) service;
                                mService = binder.getService();
                        }

                        @Override
                        public void onServiceDisconnected(ComponentName arg0) {
                        }
                };

                Intent intent = new Intent(context, OverlayService.class);
                context.bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
                mService.setText("Sending a test message");

You would of course need to destroy that service as soon as the user leaves the app if you don't want it to be on top of other apps.

Henrique
  • 4,921
  • 6
  • 36
  • 61
  • 1
    Doesn't this require a permission though? – telkins Jan 30 '14 at 20:12
  • Ah ha, good point, yes it does. Can't remember which one, but I think it was SYSTEM_ALERT_WINDOW. – Henrique Jan 30 '14 at 20:27
  • I need one without "draw on other apps" permission. – roiberg Jan 31 '14 at 15:36
  • Yeah, I saw that after I replied ha. What about creating a custom Toast message? You can add your own custom layout to the Toast and and also, you can pretty much keep a Toast open for whatever amount of time you want. Here's a simple hack I developed a couple of years ago: https://github.com/quiqueqs/Toast-Expander – Henrique Jan 31 '14 at 15:38
  • But that would be a default Toast... I need a complex View. with linear layout and two buttons.. – roiberg Jan 31 '14 at 15:45
  • You can actually customize the layout of the Toast. I have an app which does that, checkout the screenshots here, those little yellow post it notes are actually Toast messages: https://play.google.com/store/apps/details?id=com.thirtymatches.calleridnotes.lite – Henrique Jan 31 '14 at 15:53
  • Here's a link on how to customize Toast layout: http://www.learn-android-easily.com/2013/05/customiozing-toast-in-android.html – Henrique Jan 31 '14 at 15:53
  • Thanks, I know I can customise it. but I sure can't add animation.. The animation part is very important. I also need it to be clickable, could it be clickable with a custom Toast? – roiberg Jan 31 '14 at 15:56
  • 1
    You got me there. I don't think Toasts support click events. Maybe you can have a look a the actual Toast source code and see if you can at least figure out the view on top of other views part: https://github.com/android/platform_frameworks_base/blob/master/core/java/android/widget/Toast.java Good luck! – Henrique Jan 31 '14 at 15:59
  • @roiberg how did you meet your requirement? I have same requirement and looking for solution since last three days. Your guidance would make my day.. – Rozina Oct 17 '19 at 07:28