Move HAS_TRANSIENT_STATE flag into a safe area.

Previously, this flag conflicted with other text direction flags,
which can cause weird interactions across the View hierarchy,
specifically with ListView.

Also adds dumpFlags() utility to dump values of all know flags for
documentation and sanity checking.

Bug: 7189738
Change-Id: Iceb2f93f68a800e19a5889ced93abcce4932b067
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 0f8a491..87221e0 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -83,12 +83,18 @@
 import com.android.internal.R;
 import com.android.internal.util.Predicate;
 import com.android.internal.view.menu.MenuBuilder;
+import com.google.android.collect.Lists;
+import com.google.android.collect.Maps;
 
 import java.lang.ref.WeakReference;
+import java.lang.reflect.Field;
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
 import java.util.Locale;
 import java.util.concurrent.CopyOnWriteArrayList;
 import java.util.concurrent.atomic.AtomicInteger;
@@ -1727,7 +1733,51 @@
      */
     static final int PFLAG_INVALIDATED                 = 0x80000000;
 
-    /* Masks for mPrivateFlags2 */
+    /**
+     * Masks for mPrivateFlags2, as generated by dumpFlags():
+     *
+     * -------|-------|-------|-------|
+     *                                  PFLAG2_TEXT_ALIGNMENT_FLAGS[0]
+     *                                  PFLAG2_TEXT_DIRECTION_FLAGS[0]
+     *                                1 PFLAG2_DRAG_CAN_ACCEPT
+     *                               1  PFLAG2_DRAG_HOVERED
+     *                               1  PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT
+     *                              11  PFLAG2_TEXT_DIRECTION_MASK_SHIFT
+     *                             1 1  PFLAG2_TEXT_DIRECTION_RESOLVED_MASK_SHIFT
+     *                             11   PFLAG2_LAYOUT_DIRECTION_MASK
+     *                             11 1 PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT
+     *                            1     PFLAG2_LAYOUT_DIRECTION_RESOLVED_RTL
+     *                            1   1 PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK_SHIFT
+     *                            1 1   PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_SHIFT
+     *                           1      PFLAG2_LAYOUT_DIRECTION_RESOLVED
+     *                           11     PFLAG2_LAYOUT_DIRECTION_RESOLVED_MASK
+     *                          1       PFLAG2_TEXT_DIRECTION_FLAGS[1]
+     *                         1        PFLAG2_TEXT_DIRECTION_FLAGS[2]
+     *                         11       PFLAG2_TEXT_DIRECTION_FLAGS[3]
+     *                        1         PFLAG2_TEXT_DIRECTION_FLAGS[4]
+     *                        1 1       PFLAG2_TEXT_DIRECTION_FLAGS[5]
+     *                        111       PFLAG2_TEXT_DIRECTION_MASK
+     *                       1          PFLAG2_TEXT_DIRECTION_RESOLVED
+     *                      1           PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT
+     *                    111           PFLAG2_TEXT_DIRECTION_RESOLVED_MASK
+     *                   1              PFLAG2_TEXT_ALIGNMENT_FLAGS[1]
+     *                  1               PFLAG2_TEXT_ALIGNMENT_FLAGS[2]
+     *                  11              PFLAG2_TEXT_ALIGNMENT_FLAGS[3]
+     *                 1                PFLAG2_TEXT_ALIGNMENT_FLAGS[4]
+     *                 1 1              PFLAG2_TEXT_ALIGNMENT_FLAGS[5]
+     *                 11               PFLAG2_TEXT_ALIGNMENT_FLAGS[6]
+     *                 111              PFLAG2_TEXT_ALIGNMENT_MASK
+     *                1                 PFLAG2_TEXT_ALIGNMENT_RESOLVED
+     *               1                  PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT
+     *             111                  PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK
+     *           11                     PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_MASK
+     *          1                       PFLAG2_HAS_TRANSIENT_STATE
+     *      1                           PFLAG2_ACCESSIBILITY_FOCUSED
+     *     1                            PFLAG2_ACCESSIBILITY_STATE_CHANGED
+     *    1                             PFLAG2_VIEW_QUICK_REJECTED
+     *   1                              PFLAG2_PADDING_RESOLVED
+     * -------|-------|-------|-------|
+     */
 
     /**
      * Indicates that this view has reported that it can accept the current drag's content.
@@ -1825,8 +1875,7 @@
      *
      * @hide
      */
-    static final int PFLAG2_HAS_TRANSIENT_STATE = 0x00000100;
-
+    static final int PFLAG2_HAS_TRANSIENT_STATE = 0x1 << 22;
 
     /**
      * Text direction is inherited thru {@link ViewGroup}
@@ -18114,4 +18163,46 @@
             return (view.mLabelForId == mLabeledId);
         }
     }
+
+    /**
+     * Dump all private flags in readable format, useful for documentation and
+     * sanity checking.
+     */
+    private static void dumpFlags() {
+        final HashMap<String, String> found = Maps.newHashMap();
+        try {
+            for (Field field : View.class.getDeclaredFields()) {
+                final int modifiers = field.getModifiers();
+                if (Modifier.isStatic(modifiers) && Modifier.isFinal(modifiers)) {
+                    if (field.getType().equals(int.class)) {
+                        final int value = field.getInt(null);
+                        dumpFlag(found, field.getName(), value);
+                    } else if (field.getType().equals(int[].class)) {
+                        final int[] values = (int[]) field.get(null);
+                        for (int i = 0; i < values.length; i++) {
+                            dumpFlag(found, field.getName() + "[" + i + "]", values[i]);
+                        }
+                    }
+                }
+            }
+        } catch (IllegalAccessException e) {
+            throw new RuntimeException(e);
+        }
+
+        final ArrayList<String> keys = Lists.newArrayList();
+        keys.addAll(found.keySet());
+        Collections.sort(keys);
+        for (String key : keys) {
+            Log.d(VIEW_LOG_TAG, found.get(key));
+        }
+    }
+
+    private static void dumpFlag(HashMap<String, String> found, String name, int value) {
+        // Sort flags by prefix, then by bits, always keeping unique keys
+        final String bits = String.format("%32s", Integer.toBinaryString(value)).replace('0', ' ');
+        final int prefix = name.indexOf('_');
+        final String key = (prefix > 0 ? name.substring(0, prefix) : name) + bits + name;
+        final String output = bits + " " + name;
+        found.put(key, output);
+    }
 }