Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Whoa, Views can do that? WindowManager ideas an...

Whoa, Views can do that? WindowManager ideas and tricks!

https://youtu.be/ujfe_IF1O4A
Android WindowManager Ideas and Floating Views

Eric Cochran

August 28, 2015
Tweet

More Decks by Eric Cochran

Other Decks in Programming

Transcript

  1. ERIC COCHRAN WHOA, VIEWS CAN DO THAT? WINDOWMANAGER IDEAS AND

    TRICKS! @ERIC_COCHRAN DROIDCON NYC AUGUST 28, 2015
  2. BEYOND SCREENS • VIEWS THAT ARE NOT ATTACHED TO AN

    ACTIVITY’S WINDOW • REAL, FULL-FLEDGED VIEWS
  3. PERMISSION <uses-permission android:name=“android.permission.SYSTEM_ALERT_WINDOW"/> Android M: hidden setting if (!Settings.canDrawOverlays(this)) {


    Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION,
 Uri.parse("package:" + activity.getPackageName()));
 activity.startActivityForResult(intent, REQUEST_CODE_PERMISION_SYSTEM_ALERT_WINDOW);
 } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) {
 if (requestCode == REQUEST_CODE_PERMISION_SYSTEM_ALERT_WINDOW) {
 if (Settings.canDrawOverlays(this)) {
 // yay!
 } else {
 // denied
 }
 }
 }
  4. ADDING THE VIEWS 
 WindowManager windowManager =
 (WindowManager) context.getSystemService(WINDOW_SERVICE);
 View

    floatingView = new View(context);
 // background to see View
 floatingView.setBackgroundColor(Color.RED);
 WindowManager.LayoutParams floatingLayoutParams =
 new WindowManager.LayoutParams(floatingViewWidth, floatingViewHeight,
 WindowManager.LayoutParams.TYPE_PHONE,
 WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
 | WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS,
 PixelFormat.TRANSPARENT);
 floatingLayoutParams.gravity = Gravity.LEFT | Gravity.TOP;
 windowManager.addView(floatingView, floatingLayoutParams);
  5. FLAG_NOT_FOCUSABLE Views will not receive focus. No EditTexts. WI FLAG_NOT_TOUCHABLE

    No touch listeners will work. FLAG_NOT_TOUCH_MODAL Will allow touch events to pass to outside Views FLAG_LAYOUT_NO_LIMITS Views are free to move offscreen. FLAG_LAYOUT_IN_SCREEN Keep Views bounded by the screen’s dimensions.
  6. TO A SERVICE @Override public int onStartCommand(Intent intent, int flags,

    int startId) {
 // addView code
 Notification notification = // valid notification
 startForeground(id, notification);
 return START_STICKY;
 }
  7. GET MOVING floatingView.setOnTouchListener(new View.OnTouchListener() {
 
 private int downX;
 private

    int downY;
 private float touchDownX;
 private float touchDownY;
 
 @Override public boolean onTouch(View v, MotionEvent event) {
 
 switch (event.getActionMasked()) {
 case MotionEvent.ACTION_DOWN:
 downX = floatingLayoutParams.x;
 downY = floatingLayoutParams.y;
 touchDownX = event.getRawX();
 touchDownY = event.getRawY();
 break;
 case MotionEvent.ACTION_MOVE:
 floatingLayoutParams.x = (int) (downX + event.getRawX() - touchDownX);
 floatingLayoutParams.y = (int) (downY + event.getRawY() - touchDownY);
 windowManager.updateViewLayout(floatingView, floatingLayoutParams);
 break;
 default:
 break;
 }
 return true;
 }
 });
  8. FIRST IDEA (NOT-SO-GREAT) • MAKE THE ROOT VIEW THAT IS

    ATTACHED TO THE WINDOW MANAGER ALWAYS LARGE ENOUGH TO ACCOMMODATE THE MAXIMUM SCALE THAT THE CORE VIEW WILL EVER ACHIEVE. • ADD A MARGIN TO THE CORE VIEW THAT FILLS THE SPACE. • WHEN THE CORE VIEW SCALES, THE MARGIN WILL BE THE ONLY PART CLIPPED.
  9. • DISADVANTAGE OF A LARGER ROOT VIEW THAT WILL NOW

    BLOCK MORE UI FROM THE USER. • WORSE, THIS ADDED MARGIN IS INVISIBLE AND COULD LEAD TO THE USER NOT UNDERSTANDING WHY OUR FLOATING VIEW IS INTERCEPTING TOUCH EVENTS OUTSIDE OF THE VISIBLE UI. FIRST IDEA (NOT-SO-GREAT)
  10. FIRST IDEA (NOT-SO-GREAT) • ROOT VIEW ACCOUNTS FOR THE CORE

    VIEW (THE RED DOT) SCALING TO TWICE AS LARGE • BUT, THE ROOT VIEW IS NOW OBSTRUCTING OTHER TOUCH EVENTS WITHOUT THE USER REALIZING IT.
  11. • DYNAMICALLY SCALE THE ROOT VIEW BETTER METHOD 
 floatingLayoutParams.width

    *= scaleFactorX;
 floatingLayoutParams.height *= scaleFactorY;
 windowManager.updateViewLayout(floatingView, floatingLayoutParams);
  12. BETTER IDEA • WE HAVE JUST SCALED THE WIDTH AND

    THE HEIGHT WHILE LEAVING THE X AND Y FIELDS IN PLACE. PROBABLY NOT IDEAL. • TO SCALE RADIALLY: 
 floatingLayoutParams.x -= (int) ((scaleFactorX - 1f) * floatingLayoutParams.width / 2f);
 floatingLayoutParams.y -= (int) ((scaleFactorY - 1f) * floatingLayoutParams.height / 2f);
  13. REMOVE WINDOW VIEWS • REMOVE VIEWS WHERE APPROPRIATE TO PREVENT

    LEAKS • (PROBABLY IN ONDESTROY() OF A SERVICE)
  14. • DEFINE YOUR BOUNDS • WITH INSETS, CHECK AGAINST BOUNDS

    BEFORE MOVING IN TOUCH LISTENER • VIEW.GETLOCATIONONSCREEN • ADD A VELOCITY TRACKER TIPS