title: Android View resize and WindowManager: unwanted transition during child view placement
body: <p>I'm having some problems in avoiding an unwanted transition during child view placement in a custom <code>ViewGroup</code> after parent view resizing. This problem seems to be only present when using the <code>WindowManager</code> instead of the call to <code>setContentView()</code>. Here is a short example: </p>
  
  <p><code>MainActivity</code>:</p>
  
  <pre><code>public class MainActivity extends AppCompatActivity {
  
      private static final int MY_PERMISSIONS_DRAW_OVER_OTHER_APPS = 1;
      CustomViewGroup mCustomViewGroup;
      WindowManager mWindowManager;
  
      @Override
      protected void onCreate(Bundle savedInstanceState) {
          super.onCreate(savedInstanceState);
  //        setContentView(R.layout.activity_main);
  
  
          if (Build.VERSION.SDK_INT &gt;= Build.VERSION_CODES.M &amp;&amp; !Settings.canDrawOverlays(this)) {
  
              Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION,
                      Uri.parse("package:" + getPackageName()));
              startActivityForResult(intent, MY_PERMISSIONS_DRAW_OVER_OTHER_APPS);
          }
  
  
          if (Build.VERSION.SDK_INT &gt;= Build.VERSION_CODES.M &amp;&amp; !Settings.canDrawOverlays(this)) {
              if (ContextCompat.checkSelfPermission(this,
                      android.Manifest.permission.SYSTEM_ALERT_WINDOW)
                      != PackageManager.PERMISSION_GRANTED) {
  
                  if (ActivityCompat.shouldShowRequestPermissionRationale(this,
                          android.Manifest.permission.SYSTEM_ALERT_WINDOW)) {
  
  
                  } else {
  
                      ActivityCompat.requestPermissions(this,
                              new String[]{android.Manifest.permission.SYSTEM_ALERT_WINDOW},
                              MY_PERMISSIONS_DRAW_OVER_OTHER_APPS);
                  }
              }
          }
  
          mCustomViewGroup =
                  (CustomViewGroup) LayoutInflater.from(this).inflate(R.layout.activity_main,null);
  
          final WindowManager.LayoutParams floatingViewLayoutParams = new WindowManager.LayoutParams(
                  WindowManager.LayoutParams.WRAP_CONTENT,
                  WindowManager.LayoutParams.WRAP_CONTENT,
                  WindowManager.LayoutParams.TYPE_PHONE,
                  WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
                  PixelFormat.TRANSLUCENT
          );
          floatingViewLayoutParams.gravity = Gravity.BOTTOM | Gravity.LEFT;
          mWindowManager = (WindowManager) getSystemService(WINDOW_SERVICE);
          mWindowManager.addView(mCustomViewGroup,floatingViewLayoutParams);
  
  
      }
  
      @Override
      protected void onActivityResult(int requestCode, int resultCode, Intent data) {
          if (requestCode == MY_PERMISSIONS_DRAW_OVER_OTHER_APPS) {
              //Check if the permission is granted or not.
              if (resultCode == RESULT_OK) {
              } else {
                  Toast.makeText(this,
                          "Draw over other app permission not available. Closing the application",
                          Toast.LENGTH_SHORT).show();
  
                  finish();
              }
          } else {
              super.onActivityResult(requestCode, resultCode, data);
          }
      }
  
  }
  </code></pre>
  
  <p><code>CustomViewGroup</code>:</p>
  
  <pre><code>public class CustomViewGroup extends ViewGroup {
  
      private boolean mIsTouchEventActive;
  
      public CustomViewGroup(Context context) {
          this(context,null,0);
      }
  
      public CustomViewGroup(Context context, AttributeSet attrs) {
          this(context,attrs,0);
      }
  
      public CustomViewGroup(Context context, AttributeSet attrs, int defStyleAttr) {
          super(context, attrs, defStyleAttr);
          init(context);
      }
  
      private void init(Context context) {
  
          mIsTouchEventActive = false;
          setWillNotDraw(false);
  
          // Add the fab view
          LayoutInflater layoutInflater = LayoutInflater.from(context);
          View fabView = layoutInflater.inflate(R.layout.fab_view,null,false);
          this.addView(fabView);
      }
  
      @Override
      public boolean shouldDelayChildPressedState() {
          return false;
      }
  
      @Override
      public boolean onInterceptTouchEvent(MotionEvent ev) {
          return true;
      }
  
      @Override
      public boolean onTouchEvent(MotionEvent event) {
  
  
          switch (event.getAction()) {
  
              case MotionEvent.ACTION_DOWN:
                  mIsTouchEventActive = true;
                  requestLayout();
                  return true;
  
              case MotionEvent.ACTION_UP:
                  mIsTouchEventActive = false;
                  requestLayout();
                  return true;
  
          }
          return false;
  
      }
  
      @Override
      protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
  
  
          int maxHeight = 0;
          int maxWidth = 0;
          int childState = 0;
  
          final View child = getChildAt(0);
          if (child.getVisibility() != GONE) {
  
              measureChild(child, widthMeasureSpec, heightMeasureSpec);
              maxWidth = Math.max(maxWidth, child.getMeasuredWidth());
              maxHeight = Math.max(maxHeight, child.getMeasuredHeight());
              childState = combineMeasuredStates(childState, child.getMeasuredState());
  
          }
  
          maxHeight = Math.max(maxHeight, getSuggestedMinimumHeight());
          maxWidth = Math.max(maxWidth, getSuggestedMinimumWidth());
          if (mIsTouchEventActive == true) {
  
              final Display display = ((WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();
              Point deviceDisplay = new Point();
              display.getSize(deviceDisplay);
  
              maxHeight = deviceDisplay.x;
              maxWidth = deviceDisplay.y;
          }
  
  
          setMeasuredDimension(resolveSizeAndState(maxWidth, widthMeasureSpec, childState),
                  resolveSizeAndState(maxHeight, heightMeasureSpec, childState &lt;&lt; MEASURED_HEIGHT_STATE_SHIFT));
  
      }
  
      @Override
      protected void onLayout(boolean changed, int l, int t, int r, int b) {
  
          final Rect fabChildRect = new Rect();
          final View child = getChildAt(0);
          if (child.getVisibility() != GONE) {
  
              final int width = child.getMeasuredWidth();
              final int height = child.getMeasuredHeight();
  
              fabChildRect.left = 0;
              fabChildRect.right = width;
              fabChildRect.top = 0;
              fabChildRect.bottom = height;
  
              child.layout(fabChildRect.left, fabChildRect.top,
                      fabChildRect.right, fabChildRect.bottom);
  
          }
      }
  }
  </code></pre>
  
  <p><code>activity_main.xml</code>:</p>
  
  <pre><code>&lt;?xml version="1.0" encoding="utf-8"?&gt;
  &lt;packagename.CustomViewGroup
      xmlns:android="http://schemas.android.com/apk/res/android"
      android:id="@+id/custom_view_group"
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:layout_alignParentBottom="true"
      android:layout_alignParentLeft="true"/&gt;
  </code></pre>
  
  <p><code>fab_view.xml</code></p>
  
  <pre><code>&lt;?xml version="1.0" encoding="utf-8"?&gt;
  &lt;LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
                xmlns:app="http://schemas.android.com/apk/res-auto"
                android:orientation="vertical"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"&gt;
  
      &lt;android.support.design.widget.FloatingActionButton
          xmlns:android="http://schemas.android.com/apk/res/android"
          xmlns:app="http://schemas.android.com/apk/res-auto"
          android:id="@+id/fab"
          android:layout_width="wrap_content"
          android:layout_height="wrap_content"
          android:layout_margin="16dp"
          app:srcCompat="@android:drawable/ic_dialog_email"/&gt;
  
  &lt;/LinearLayout&gt;
  </code></pre>
  
  <p>The manifest file should contain the <code>android.permission.SYSTEM_ALERT_WINDOW</code> permission and my dependency list in <code>build.gradle</code> is the following:</p>
  
  <pre><code>dependencies {
      compile fileTree(dir: 'libs', include: ['*.jar'])
      androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
          exclude group: 'com.android.support', module: 'support-annotations'
      })
      compile 'com.android.support:appcompat-v7:24.2.1'
      compile 'com.android.support.constraint:constraint-layout:1.0.2'
      compile 'com.android.support:design:24.2.1'
      testCompile 'junit:junit:4.12'
  }
  </code></pre>
  
  <p>Here is what I'm doing: </p>
  
  <p>I have a custom view <code>CustomViewGroup</code> inheriting from <code>ViewGroup</code> which in my short example contains a <code>FloatingActionButton</code>, placed in the bottom-left corner of the parent view. The default sizes of <code>CustomViewGroup</code> are those of the contained <code>FloatingActionButton</code>: 264x264. </p>
  
  <p>I've implemented the <code>onClick</code> and <code>onMeasure</code> methods in <code>CustomViewGroup</code> so that in case of an <code>ACTION_DOWN</code> event the size of <code>CustomViewGroup</code> is expanded to the whole display. In case of a <code>ACTION_UP</code> event the size returns to the default one. The position of the <code>FloatingActionButton</code> within the <code>CustomViewGroup</code> is always </p>
  
  <pre><code>fabChildRect.left = 0;
  fabChildRect.right = width;
  fabChildRect.top = 0;
  fabChildRect.bottom = height;
  </code></pre>
  
  <p>where <code>width</code> and <code>height</code> are both equal to 264, therefore the button itself is placed in different positions when the parent view sizes change after a user touch.</p>
  
  <p>My question is: how can be removed the animation during the action button placement in case of a user touch event? I mean the vertical motion of the button view. I have already tried with the <code>disableTransitionType</code> method with all the transition types but nothing changes. Same if I try to disable the transitions in the xml files. This transition is not present if the <code>CustomViewGroup</code> view is added to the main activity view by inflating it from the xml instead of using the <code>WindowManager</code>, for example with the following <code>activity_main.xml</code></p>
  
  <pre><code>&lt;?xml version="1.0" encoding="utf-8"?&gt;
  &lt;RelativeLayout
      android:id="@+id/activity_main"
      xmlns:android="http://schemas.android.com/apk/res/android"
      xmlns:tools="http://schemas.android.com/tools"
      android:layout_width="match_parent"
      android:layout_height="match_parent"
      tools:context="packagename.MainActivity"&gt;
  
      &lt;packagename.CustomViewGroup
      xmlns:android="http://schemas.android.com/apk/res/android"
          android:id="@+id/custom_view_group"
          android:layout_width="wrap_content"
          android:layout_height="wrap_content"
          android:layout_alignParentBottom="true"
          android:layout_alignParentLeft="true"/&gt;
  
  &lt;/RelativeLayout&gt;
  </code></pre>
  
  <p>Do you have any advice on how to solve my problem and maybe also an explanation for what I'm observing? As you can probably guess from my code I'm a beginner in Android programming so any advice in general also not strictly related to the topic of this thread is more than welcome!</p>
  
  <p>Thank you.</p>
  
  <p>UPDATE: I've found that using the <code>WindowManager</code> there is a call to </p>
  
  <pre><code>int relayoutResult = mWindowSession.relayout(
      mWindow, mSeq, params,
      (int) (mView.getMeasuredWidth() * appScale + 0.5f),
      (int) (mView.getMeasuredHeight() * appScale + 0.5f),
      viewVisibility, 
      insetsPending ? WindowManagerGlobal.RELAYOUT_INSETS_PENDING : 0,mWinFrame, 
      mPendingOverscanInsets, mPendingContentInsets, mPendingVisibleInsets,
      mPendingStableInsets, mPendingOutsets, mPendingConfiguration, mSurface);
  </code></pre>
  
  <p>within <code>ViewRootImpl</code> (line 5415) and the unwanted visible transition is performed during the execution of this method. If I inflate the <code>CustomViewGroup</code> from the xml in the main activity the above method is not called in case of a touch event and since in this condition also the transition is not visible I guess that I can consider the <code>relayout</code> method of the <code>mWindowSession</code> data member (type is <code>IWindowSession</code>) its responsible. </p>