1/*
2 * Copyright (C) 2013 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17
18package android.support.v4.view;
19
20import android.graphics.Rect;
21import android.os.Build;
22import android.view.Gravity;
23
24/**
25 * Compatibility shim for accessing newer functionality from {@link android.view.Gravity}.
26 */
27public class GravityCompat {
28    interface GravityCompatImpl {
29        int getAbsoluteGravity(int gravity, int layoutDirection);
30        void apply(int gravity, int w, int h, Rect container, Rect outRect, int layoutDirection);
31        void apply(int gravity, int w, int h, Rect container, int xAdj, int yAdj,
32                Rect outRect, int layoutDirection);
33        void applyDisplay(int gravity, Rect display, Rect inoutObj, int layoutDirection);
34    }
35
36    static class GravityCompatImplBase implements GravityCompatImpl {
37        @Override
38        public int getAbsoluteGravity(int gravity, int layoutDirection) {
39            // Just strip off the relative bit to get LEFT/RIGHT.
40            return gravity & ~RELATIVE_LAYOUT_DIRECTION;
41        }
42
43        @Override
44        public void apply(int gravity, int w, int h, Rect container, Rect outRect,
45                int layoutDirection) {
46            Gravity.apply(gravity, w, h, container, outRect);
47        }
48
49        @Override
50        public void apply(int gravity, int w, int h, Rect container, int xAdj, int yAdj,
51                Rect outRect, int layoutDirection) {
52            Gravity.apply(gravity, w, h, container, xAdj, yAdj, outRect);
53        }
54
55        @Override
56        public void applyDisplay(int gravity, Rect display, Rect inoutObj,
57                int layoutDirection) {
58            Gravity.applyDisplay(gravity, display, inoutObj);
59        }
60    }
61
62    static class GravityCompatImplJellybeanMr1 implements GravityCompatImpl {
63        @Override
64        public int getAbsoluteGravity(int gravity, int layoutDirection) {
65            return GravityCompatJellybeanMr1.getAbsoluteGravity(gravity, layoutDirection);
66        }
67
68        @Override
69        public void apply(int gravity, int w, int h, Rect container, Rect outRect,
70                int layoutDirection) {
71            GravityCompatJellybeanMr1.apply(gravity, w, h, container, outRect, layoutDirection);
72        }
73
74        @Override
75        public void apply(int gravity, int w, int h, Rect container, int xAdj, int yAdj,
76                Rect outRect, int layoutDirection) {
77            GravityCompatJellybeanMr1.apply(gravity, w, h, container, xAdj, yAdj, outRect,
78                    layoutDirection);
79        }
80
81        @Override
82        public void applyDisplay(int gravity, Rect display, Rect inoutObj, int layoutDirection) {
83            GravityCompatJellybeanMr1.applyDisplay(gravity, display, inoutObj, layoutDirection);
84        }
85    }
86
87    static final GravityCompatImpl IMPL;
88    static {
89        final int version = Build.VERSION.SDK_INT;
90        if (version >= 17) {
91            IMPL = new GravityCompatImplJellybeanMr1();
92        } else {
93            IMPL = new GravityCompatImplBase();
94        }
95    }
96
97    /** Raw bit controlling whether the layout direction is relative or not (START/END instead of
98     * absolute LEFT/RIGHT).
99     */
100    public static final int RELATIVE_LAYOUT_DIRECTION = 0x00800000;
101
102    /** Push object to x-axis position at the start of its container, not changing its size. */
103    public static final int START = RELATIVE_LAYOUT_DIRECTION | Gravity.LEFT;
104
105    /** Push object to x-axis position at the end of its container, not changing its size. */
106    public static final int END = RELATIVE_LAYOUT_DIRECTION | Gravity.RIGHT;
107
108    /**
109     * Binary mask for the horizontal gravity and script specific direction bit.
110     */
111    public static final int RELATIVE_HORIZONTAL_GRAVITY_MASK = START | END;
112
113    /**
114     * Apply a gravity constant to an object and take care if layout direction is RTL or not.
115     *
116     * @param gravity The desired placement of the object, as defined by the
117     *                constants in this class.
118     * @param w The horizontal size of the object.
119     * @param h The vertical size of the object.
120     * @param container The frame of the containing space, in which the object
121     *                  will be placed.  Should be large enough to contain the
122     *                  width and height of the object.
123     * @param outRect Receives the computed frame of the object in its
124     *                container.
125     * @param layoutDirection The layout direction.
126     *
127     * @see ViewCompat#LAYOUT_DIRECTION_LTR
128     * @see ViewCompat#LAYOUT_DIRECTION_RTL
129     */
130    public static void apply(int gravity, int w, int h, Rect container,
131            Rect outRect, int layoutDirection) {
132        IMPL.apply(gravity, w, h, container, outRect, layoutDirection);
133    }
134
135    /**
136     * Apply a gravity constant to an object.
137     *
138     * @param gravity The desired placement of the object, as defined by the
139     *                constants in this class.
140     * @param w The horizontal size of the object.
141     * @param h The vertical size of the object.
142     * @param container The frame of the containing space, in which the object
143     *                  will be placed.  Should be large enough to contain the
144     *                  width and height of the object.
145     * @param xAdj Offset to apply to the X axis.  If gravity is LEFT this
146     *             pushes it to the right; if gravity is RIGHT it pushes it to
147     *             the left; if gravity is CENTER_HORIZONTAL it pushes it to the
148     *             right or left; otherwise it is ignored.
149     * @param yAdj Offset to apply to the Y axis.  If gravity is TOP this pushes
150     *             it down; if gravity is BOTTOM it pushes it up; if gravity is
151     *             CENTER_VERTICAL it pushes it down or up; otherwise it is
152     *             ignored.
153     * @param outRect Receives the computed frame of the object in its
154     *                container.
155     * @param layoutDirection The layout direction.
156     *
157     * @see ViewCompat#LAYOUT_DIRECTION_LTR
158     * @see ViewCompat#LAYOUT_DIRECTION_RTL
159     */
160    public static void apply(int gravity, int w, int h, Rect container,
161            int xAdj, int yAdj, Rect outRect, int layoutDirection) {
162        IMPL.apply(gravity, w, h, container, xAdj, yAdj, outRect, layoutDirection);
163    }
164
165    /**
166     * Apply additional gravity behavior based on the overall "display" that an
167     * object exists in.  This can be used after
168     * {@link android.view.Gravity#apply(int, int, int, Rect, int, int, Rect)} to place the object
169     * within a visible display.  By default this moves or clips the object
170     * to be visible in the display; the gravity flags
171     * {@link android.view.Gravity#DISPLAY_CLIP_HORIZONTAL} and
172     * {@link android.view.Gravity#DISPLAY_CLIP_VERTICAL} can be used to change this behavior.
173     *
174     * @param gravity Gravity constants to modify the placement within the
175     * display.
176     * @param display The rectangle of the display in which the object is
177     * being placed.
178     * @param inoutObj Supplies the current object position; returns with it
179     * modified if needed to fit in the display.
180     * @param layoutDirection The layout direction.
181     *
182     * @see ViewCompat#LAYOUT_DIRECTION_LTR
183     * @see ViewCompat#LAYOUT_DIRECTION_RTL
184     */
185    public static void applyDisplay(int gravity, Rect display, Rect inoutObj, int layoutDirection) {
186        IMPL.applyDisplay(gravity, display, inoutObj, layoutDirection);
187    }
188
189    /**
190     * <p>Convert script specific gravity to absolute horizontal value.</p>
191     *
192     * if horizontal direction is LTR, then START will set LEFT and END will set RIGHT.
193     * if horizontal direction is RTL, then START will set RIGHT and END will set LEFT.
194     *
195     *
196     * @param gravity The gravity to convert to absolute (horizontal) values.
197     * @param layoutDirection The layout direction.
198     * @return gravity converted to absolute (horizontal) values.
199     */
200    public static int getAbsoluteGravity(int gravity, int layoutDirection) {
201        return IMPL.getAbsoluteGravity(gravity, layoutDirection);
202    }
203}
204