2

How can I control the position of window?

I added the SurfaceView with WindowManager.LayoutParam into the WindowManager; And I tried to change the x and y of WindowManager.LayoutParams in Thread; But I only got the Wrong Thread Exception.

SurfaceViewDemoActivity .java

public class SurfaceViewDemoActivity extends Activity {
    private MySurfaceView mySurfaceView;
    private FloatingWindow floatingWindow;
    private int x = 0;
    private Thread t;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);           
        int imgId = R.drawable.bubble;
        mySurfaceView = new MySurfaceView(this, imgId);
        floatingWindow = new FloatingWindow(this, mySurfaceView, 0, 0);        

        t = new Thread(new Runnable(){
                public void run() {
                    while (true) {
                        if (x > 150) x = 0;
                        //The problem is here.
                        floatingWindow.update(mySurfaceView, x, x);
                        x++;
                    }   
                }
        });     
         t.start();
    }
}

FloatingWindow .java

public class FloatingWindow {
    private WindowManager windowManager;  
    private WindowManager.LayoutParams layoutParams; 
    private boolean hasViewAdded = false;

    public final void update (View view, int coordX, int coordY) {
        update(coordX, coordY);
        update(view);
    }    

    public final void update (View view) {
        if ( isViewAdded() == true ) {
            windowManager.updateViewLayout(view, layoutParams);
        } else {    
            windowManager.addView(view, layoutParams);
            setViewAdded(true); 
        }
    }

    private final void update (int coordX, int coordY) {
        this.layoutParams.gravity = Gravity.LEFT | Gravity.TOP;
        this.layoutParams.x = coordX;
        this.layoutParams.y = coordY;       
    }

    private void updateSize (View view) {
        int width = view.getWidth();
        int height = view.getHeight();
        this.layoutParams.width = width;  
        this.layoutParams.height = height;
    } 

    public FloatingWindow (Context context, View view, int coordX, int coordY) {
        init(context);
        updateSize(view);
        update(view, coordX, coordY);
    }   

    private void init(Context context) {
        this.windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
        this.layoutParams = new WindowManager.LayoutParams();
        this.layoutParams.type = WindowManager.LayoutParams.TYPE_SYSTEM_ALERT;  
        this.layoutParams.flags = LayoutParams.FLAG_NOT_TOUCH_MODAL | LayoutParams.FLAG_NOT_FOCUSABLE;
        this.layoutParams.format = PixelFormat.TRANSPARENT;
    }   

    protected boolean isViewAdded () {
        return this.hasViewAdded;
    }

    protected void setViewAdded (boolean hasViewAdded) {
        this.hasViewAdded = hasViewAdded;
    }
}

AndroidManifest.xml

<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>

Log.txt

E/Trace(5041):      error opening trace file: No such file or directory (2)
W/Trace(5041):      Unexpected value from nativeGetEnabledTags: 0

I/Choreographer(5041):  Skipped 128 frames!  The application may be doing too much work on its main thread.

W/Trace(5041):      Unexpected value from nativeGetEnabledTags: 0
W/dalvikvm(5041):   threadid=11: thread exiting with uncaught exception (group=0xb5cff908)

E/AndroidRuntime(5041): FATAL EXCEPTION: Thread-252
E/AndroidRuntime(5041): android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.

E/AndroidRuntime(5041):     at android.view.ViewRootImpl.checkThread(ViewRootImpl.java:4746)
E/AndroidRuntime(5041):     at android.view.ViewRootImpl.requestLayout(ViewRootImpl.java:823)

E/AndroidRuntime(5041):     at android.view.View.requestLayout(View.java:15468)
E/AndroidRuntime(5041):     at android.view.View.setLayoutParams(View.java:10022)
E/AndroidRuntime(5041):     at android.view.WindowManagerGlobal.updateViewLayout(WindowManagerGlobal.java:269)

E/AndroidRuntime(5041):     at android.view.WindowManagerImpl.updateViewLayout(WindowManagerImpl.java:74)
E/AndroidRuntime(5041):     at com.givemepass.surfaceview.FloatingWindow.update(FloatingWindow.java:27)
E/AndroidRuntime(5041):     at com.givemepass.surfaceview.FloatingWindow.update(FloatingWindow.java:18)

E/AndroidRuntime(5041):     at com.givemepass.surfaceview.SurfaceViewDemoActivity$1.run(SurfaceViewDemoActivity.java:33)
E/AndroidRuntime(5041):     at java.lang.Thread.run(Thread.java:856)

W/Trace(5041):      Unexpected value from nativeGetEnabledTags: 0
D/gralloc_goldfish(5041): Emulator without GPU emulation detected.
W/Trace(5041):      Unexpected value from nativeGetEnabledTags: 0

I/Choreographer(5041):  Skipped 671 frames!  The application may be doing too much work on its main thread.
W/Trace(5041):      Unexpected value from nativeGetEnabledTags: 0

W/Trace(5041):      Unexpected value from nativeGetEnabledTags: 0
A/libc(5041):       Fatal signal 11 (SIGSEGV) at 0xae3e1000 (code=1), thread 5057 (Thread-253)
I/Process(5041):    Sending signal. PID: 5041 SIG: 9

user15
  • 1,038
  • 10
  • 19
Yen
  • 19
  • 1
  • 6

2 Answers2

0

After you added the 'SurfaceView' into 'WindowManager', just change the 'x' and 'y' of WindowManager.LayoutParams.

If you had the 'Thread Exception' and message('Only the original thread that created a view hierarchy can touch its views.')like me, you can read Painless threading on 'Android Developers Blog'.

Thread t = new Thread(new Runnable(){
        public void run() {
            while (true) {
                if ( x > 150 ) x = 0;
                runOnUiThread(new Runnable() {
                    public void run() {
                        //Update the UI here.
                        floatingWindow.update(mySurfaceView, x, x);
                    }
                });
                x++; 
            }   
        }
    });

Yen
  • 19
  • 1
  • 6
0

You have to use Activity.runOnUiThread(Runnable action) or create Handler in the UI thread and pass coordinates via message. The GUI framework is not thread safe in the android. So android's developers decided to notify everyone about mistake if somebody tries to work with UI from another thread.