Add a remote control mechanism for window containers

This adds a "IWindowContainer" interface which is an opaque
handle to a window-container in WM. It has very minimal
functionality and is intended to be used mostly as an
identifier.

Along with this handle, there is a WindowContainerTransaction
which can collect a set of container + configuration changess
and apply them all together. This will be used for remote
rotation control and other batched operations in the future.

Bug: 124011688
Test: Added some wm/core tests.
Change-Id: I691e7c11cd8c30f1a24fd64c6018a18933047847
diff --git a/core/java/android/view/WindowContainerTransaction.java b/core/java/android/view/WindowContainerTransaction.java
new file mode 100644
index 0000000..607a870
--- /dev/null
+++ b/core/java/android/view/WindowContainerTransaction.java
@@ -0,0 +1,173 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view;
+
+import android.app.WindowConfiguration;
+import android.content.pm.ActivityInfo;
+import android.content.res.Configuration;
+import android.graphics.Rect;
+import android.os.IBinder;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.util.ArrayMap;
+
+import java.util.Map;
+
+/**
+ * Represents a collection of operations on some WindowContainers that should be applied all at
+ * once.
+ *
+ * @hide
+ */
+public class WindowContainerTransaction implements Parcelable {
+    private final ArrayMap<IBinder, Change> mChanges = new ArrayMap<>();
+
+    public WindowContainerTransaction() {}
+
+    protected WindowContainerTransaction(Parcel in) {
+        in.readMap(mChanges, null /* loader */);
+    }
+
+    private Change getOrCreateChange(IBinder token) {
+        Change out = mChanges.get(token);
+        if (out == null) {
+            out = new Change();
+            mChanges.put(token, out);
+        }
+        return out;
+    }
+
+    /**
+     * Resize a container.
+     */
+    public WindowContainerTransaction setBounds(IWindowContainer container, Rect bounds) {
+        Change chg = getOrCreateChange(container.asBinder());
+        chg.mConfiguration.windowConfiguration.setBounds(bounds);
+        chg.mConfigSetMask |= ActivityInfo.CONFIG_WINDOW_CONFIGURATION;
+        chg.mWindowSetMask |= WindowConfiguration.WINDOW_CONFIG_BOUNDS;
+        return this;
+    }
+
+    public Map<IBinder, Change> getChanges() {
+        return mChanges;
+    }
+
+    @Override
+    public String toString() {
+        return "WindowContainerTransaction { changes = " + mChanges + " }";
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeMap(mChanges);
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    public static final Creator<WindowContainerTransaction> CREATOR =
+            new Creator<WindowContainerTransaction>() {
+                @Override
+                public WindowContainerTransaction createFromParcel(Parcel in) {
+                    return new WindowContainerTransaction(in);
+                }
+
+                @Override
+                public WindowContainerTransaction[] newArray(int size) {
+                    return new WindowContainerTransaction[size];
+                }
+            };
+
+    /**
+     * Holds changes on a single WindowContainer including Configuration changes.
+     *
+     * @hide
+     */
+    public static class Change implements Parcelable {
+        private final Configuration mConfiguration = new Configuration();
+        private @ActivityInfo.Config int mConfigSetMask = 0;
+        private @WindowConfiguration.WindowConfig int mWindowSetMask = 0;
+
+        public Change() {}
+
+        protected Change(Parcel in) {
+            mConfiguration.readFromParcel(in);
+            mConfigSetMask = in.readInt();
+            mWindowSetMask = in.readInt();
+        }
+
+        public Configuration getConfiguration() {
+            return mConfiguration;
+        }
+
+        @ActivityInfo.Config
+        public int getConfigSetMask() {
+            return mConfigSetMask;
+        }
+
+        @WindowConfiguration.WindowConfig
+        public int getWindowSetMask() {
+            return mWindowSetMask;
+        }
+
+        @Override
+        public String toString() {
+            final boolean changesBounds =
+                    (mConfigSetMask & ActivityInfo.CONFIG_WINDOW_CONFIGURATION) != 0
+                            && ((mWindowSetMask & WindowConfiguration.WINDOW_CONFIG_BOUNDS)
+                                    != 0);
+            final boolean changesSss =
+                    (mConfigSetMask & ActivityInfo.CONFIG_SMALLEST_SCREEN_SIZE) != 0;
+            StringBuilder sb = new StringBuilder();
+            sb.append('{');
+            if (changesBounds) {
+                sb.append("bounds:" + mConfiguration.windowConfiguration.getBounds() + ",");
+            }
+            if (changesSss) {
+                sb.append("ssw:" + mConfiguration.smallestScreenWidthDp + ",");
+            }
+            sb.append("}");
+            return sb.toString();
+        }
+
+        @Override
+        public void writeToParcel(Parcel dest, int flags) {
+            mConfiguration.writeToParcel(dest, flags);
+            dest.writeInt(mConfigSetMask);
+            dest.writeInt(mWindowSetMask);
+        }
+
+        @Override
+        public int describeContents() {
+            return 0;
+        }
+
+        public static final Creator<Change> CREATOR = new Creator<Change>() {
+            @Override
+            public Change createFromParcel(Parcel in) {
+                return new Change(in);
+            }
+
+            @Override
+            public Change[] newArray(int size) {
+                return new Change[size];
+            }
+        };
+    }
+}