146dfba6160b55a582b344328067e3dafeb881dd9Andy Huang/*
246dfba6160b55a582b344328067e3dafeb881dd9Andy Huang * Copyright (C) 2012 Google Inc.
346dfba6160b55a582b344328067e3dafeb881dd9Andy Huang * Licensed to The Android Open Source Project.
446dfba6160b55a582b344328067e3dafeb881dd9Andy Huang *
546dfba6160b55a582b344328067e3dafeb881dd9Andy Huang * Licensed under the Apache License, Version 2.0 (the "License");
646dfba6160b55a582b344328067e3dafeb881dd9Andy Huang * you may not use this file except in compliance with the License.
746dfba6160b55a582b344328067e3dafeb881dd9Andy Huang * You may obtain a copy of the License at
846dfba6160b55a582b344328067e3dafeb881dd9Andy Huang *
946dfba6160b55a582b344328067e3dafeb881dd9Andy Huang *      http://www.apache.org/licenses/LICENSE-2.0
1046dfba6160b55a582b344328067e3dafeb881dd9Andy Huang *
1146dfba6160b55a582b344328067e3dafeb881dd9Andy Huang * Unless required by applicable law or agreed to in writing, software
1246dfba6160b55a582b344328067e3dafeb881dd9Andy Huang * distributed under the License is distributed on an "AS IS" BASIS,
1346dfba6160b55a582b344328067e3dafeb881dd9Andy Huang * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1446dfba6160b55a582b344328067e3dafeb881dd9Andy Huang * See the License for the specific language governing permissions and
1546dfba6160b55a582b344328067e3dafeb881dd9Andy Huang * limitations under the License.
1646dfba6160b55a582b344328067e3dafeb881dd9Andy Huang */
1746dfba6160b55a582b344328067e3dafeb881dd9Andy Huang
1846dfba6160b55a582b344328067e3dafeb881dd9Andy Huangpackage com.android.mail.browse;
1946dfba6160b55a582b344328067e3dafeb881dd9Andy Huang
2046dfba6160b55a582b344328067e3dafeb881dd9Andy Huangimport android.content.Context;
21adbf3e8cadb66666f307352b72537fbac57b916fAndy Huangimport android.view.Gravity;
2246dfba6160b55a582b344328067e3dafeb881dd9Andy Huangimport android.view.LayoutInflater;
2346dfba6160b55a582b344328067e3dafeb881dd9Andy Huangimport android.view.View;
2446dfba6160b55a582b344328067e3dafeb881dd9Andy Huangimport android.view.ViewGroup;
2546dfba6160b55a582b344328067e3dafeb881dd9Andy Huangimport android.widget.Adapter;
2646dfba6160b55a582b344328067e3dafeb881dd9Andy Huangimport android.widget.CursorAdapter;
2746dfba6160b55a582b344328067e3dafeb881dd9Andy Huang
28e2a30e19a9fff0e4368c4ec36280a3fcd4ca03e2Andrew Sappersteinimport com.android.mail.browse.ConversationViewAdapter.ConversationViewType;
29632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huangimport com.android.mail.ui.ConversationViewFragment;
3046dfba6160b55a582b344328067e3dafeb881dd9Andy Huangimport com.android.mail.utils.LogUtils;
3146dfba6160b55a582b344328067e3dafeb881dd9Andy Huang
3246dfba6160b55a582b344328067e3dafeb881dd9Andy Huangpublic abstract class ConversationOverlayItem {
3346dfba6160b55a582b344328067e3dafeb881dd9Andy Huang    private int mHeight;  // in px
3431c38a8247b4583ac1cc506acf8454d8922ee491Andy Huang    private int mTop;  // in px
3546dfba6160b55a582b344328067e3dafeb881dd9Andy Huang    private boolean mNeedsMeasure;
3646dfba6160b55a582b344328067e3dafeb881dd9Andy Huang
37632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang    public static final String LOG_TAG = ConversationViewFragment.LAYOUT_TAG;
3846dfba6160b55a582b344328067e3dafeb881dd9Andy Huang
39cee3c90574b48ccaa0f8b9f9341383c231ed41d2Andrew Sapperstein    private int mPosition;
40cee3c90574b48ccaa0f8b9f9341383c231ed41d2Andrew Sapperstein
410b69338a45faa422ccba8faf64c9816c55d33e4aJin Cao    // The view to focus when this overlay item should be focused.
420b69338a45faa422ccba8faf64c9816c55d33e4aJin Cao    protected View mRootView;
430b69338a45faa422ccba8faf64c9816c55d33e4aJin Cao
4446dfba6160b55a582b344328067e3dafeb881dd9Andy Huang    /**
4546dfba6160b55a582b344328067e3dafeb881dd9Andy Huang     * @see Adapter#getItemViewType(int)
4646dfba6160b55a582b344328067e3dafeb881dd9Andy Huang     */
47e2a30e19a9fff0e4368c4ec36280a3fcd4ca03e2Andrew Sapperstein    public abstract @ConversationViewType int getType();
48a7404589b03ac9dd0d07b3f7d0a1ec92ac9acb62Jin Cao
4946dfba6160b55a582b344328067e3dafeb881dd9Andy Huang    /**
5046dfba6160b55a582b344328067e3dafeb881dd9Andy Huang     * Inflate and perform one-time initialization on a view for later binding.
5146dfba6160b55a582b344328067e3dafeb881dd9Andy Huang     */
5246dfba6160b55a582b344328067e3dafeb881dd9Andy Huang    public abstract View createView(Context context, LayoutInflater inflater,
5346dfba6160b55a582b344328067e3dafeb881dd9Andy Huang            ViewGroup parent);
54b8331b4565566ca733997398e8c07a26cd2bee98Andy Huang
5546dfba6160b55a582b344328067e3dafeb881dd9Andy Huang    /**
5646dfba6160b55a582b344328067e3dafeb881dd9Andy Huang     * @see CursorAdapter#bindView(View, Context, android.database.Cursor)
57b8331b4565566ca733997398e8c07a26cd2bee98Andy Huang     * @param v a view to bind to
58b8331b4565566ca733997398e8c07a26cd2bee98Andy Huang     * @param measureOnly true iff we are binding this view only to measure its height (so items
59b8331b4565566ca733997398e8c07a26cd2bee98Andy Huang     * know they can cut certain corners that do not affect a view's height)
6046dfba6160b55a582b344328067e3dafeb881dd9Andy Huang     */
61b8331b4565566ca733997398e8c07a26cd2bee98Andy Huang    public abstract void bindView(View v, boolean measureOnly);
62a7404589b03ac9dd0d07b3f7d0a1ec92ac9acb62Jin Cao
6346dfba6160b55a582b344328067e3dafeb881dd9Andy Huang    /**
6446dfba6160b55a582b344328067e3dafeb881dd9Andy Huang     * Returns true if this overlay view is meant to be positioned right on top of the overlay
6546dfba6160b55a582b344328067e3dafeb881dd9Andy Huang     * below. This special positioning allows {@link ConversationContainer} to stack overlays
6646dfba6160b55a582b344328067e3dafeb881dd9Andy Huang     * together even when zoomed into a conversation, when the overlay spacers spread farther
6746dfba6160b55a582b344328067e3dafeb881dd9Andy Huang     * apart.
6846dfba6160b55a582b344328067e3dafeb881dd9Andy Huang     */
6946dfba6160b55a582b344328067e3dafeb881dd9Andy Huang    public abstract boolean isContiguous();
7046dfba6160b55a582b344328067e3dafeb881dd9Andy Huang
71a7404589b03ac9dd0d07b3f7d0a1ec92ac9acb62Jin Cao    public View.OnKeyListener getOnKeyListener() {
72a7404589b03ac9dd0d07b3f7d0a1ec92ac9acb62Jin Cao        return null;
73a7404589b03ac9dd0d07b3f7d0a1ec92ac9acb62Jin Cao    }
74a7404589b03ac9dd0d07b3f7d0a1ec92ac9acb62Jin Cao
75cee3c90574b48ccaa0f8b9f9341383c231ed41d2Andrew Sapperstein    /**
76cee3c90574b48ccaa0f8b9f9341383c231ed41d2Andrew Sapperstein     * Returns true if this overlay view is in its expanded state.
77cee3c90574b48ccaa0f8b9f9341383c231ed41d2Andrew Sapperstein     */
78cee3c90574b48ccaa0f8b9f9341383c231ed41d2Andrew Sapperstein    public boolean isExpanded() {
79cee3c90574b48ccaa0f8b9f9341383c231ed41d2Andrew Sapperstein        return true;
80cee3c90574b48ccaa0f8b9f9341383c231ed41d2Andrew Sapperstein    }
81cee3c90574b48ccaa0f8b9f9341383c231ed41d2Andrew Sapperstein
82adbf3e8cadb66666f307352b72537fbac57b916fAndy Huang    public int getGravity() {
83adbf3e8cadb66666f307352b72537fbac57b916fAndy Huang        return Gravity.BOTTOM;
84adbf3e8cadb66666f307352b72537fbac57b916fAndy Huang    }
85adbf3e8cadb66666f307352b72537fbac57b916fAndy Huang
8646dfba6160b55a582b344328067e3dafeb881dd9Andy Huang    /**
8746dfba6160b55a582b344328067e3dafeb881dd9Andy Huang     * This method's behavior is critical and requires some 'splainin.
8846dfba6160b55a582b344328067e3dafeb881dd9Andy Huang     * <p>
8946dfba6160b55a582b344328067e3dafeb881dd9Andy Huang     * Subclasses that return a zero-size height to the {@link ConversationContainer} will
9046dfba6160b55a582b344328067e3dafeb881dd9Andy Huang     * cause the scrolling/recycling logic there to remove any matching view from the container.
9146dfba6160b55a582b344328067e3dafeb881dd9Andy Huang     * The item should switch to returning a non-zero height when its view should re-appear.
9246dfba6160b55a582b344328067e3dafeb881dd9Andy Huang     * <p>
9346dfba6160b55a582b344328067e3dafeb881dd9Andy Huang     * It's imperative that this method stay in sync with the current height of the HTML spacer
9446dfba6160b55a582b344328067e3dafeb881dd9Andy Huang     * that matches this overlay.
9546dfba6160b55a582b344328067e3dafeb881dd9Andy Huang     */
9646dfba6160b55a582b344328067e3dafeb881dd9Andy Huang    public int getHeight() {
9746dfba6160b55a582b344328067e3dafeb881dd9Andy Huang        return mHeight;
9846dfba6160b55a582b344328067e3dafeb881dd9Andy Huang    }
9946dfba6160b55a582b344328067e3dafeb881dd9Andy Huang
1007388dba58aecafacd91ded0f787cf01bfc7af232Andy Huang    /**
1017388dba58aecafacd91ded0f787cf01bfc7af232Andy Huang     * Set a new height.
1027388dba58aecafacd91ded0f787cf01bfc7af232Andy Huang     *
1037388dba58aecafacd91ded0f787cf01bfc7af232Andy Huang     * @param h a new height
1047388dba58aecafacd91ded0f787cf01bfc7af232Andy Huang     * @return true if the value changed
1057388dba58aecafacd91ded0f787cf01bfc7af232Andy Huang     */
1067388dba58aecafacd91ded0f787cf01bfc7af232Andy Huang    public boolean setHeight(int h) {
10746dfba6160b55a582b344328067e3dafeb881dd9Andy Huang        LogUtils.i(LOG_TAG, "IN setHeight=%dpx of overlay item: %s", h, this);
10846dfba6160b55a582b344328067e3dafeb881dd9Andy Huang        if (mHeight != h) {
10946dfba6160b55a582b344328067e3dafeb881dd9Andy Huang            mHeight = h;
11046dfba6160b55a582b344328067e3dafeb881dd9Andy Huang            mNeedsMeasure = true;
1117388dba58aecafacd91ded0f787cf01bfc7af232Andy Huang            return true;
11246dfba6160b55a582b344328067e3dafeb881dd9Andy Huang        }
1137388dba58aecafacd91ded0f787cf01bfc7af232Andy Huang        return false;
11446dfba6160b55a582b344328067e3dafeb881dd9Andy Huang    }
11546dfba6160b55a582b344328067e3dafeb881dd9Andy Huang
11631c38a8247b4583ac1cc506acf8454d8922ee491Andy Huang    public int getTop() {
11731c38a8247b4583ac1cc506acf8454d8922ee491Andy Huang        return mTop;
11831c38a8247b4583ac1cc506acf8454d8922ee491Andy Huang    }
11931c38a8247b4583ac1cc506acf8454d8922ee491Andy Huang
12031c38a8247b4583ac1cc506acf8454d8922ee491Andy Huang    public void setTop(int top) {
12131c38a8247b4583ac1cc506acf8454d8922ee491Andy Huang        mTop = top;
12231c38a8247b4583ac1cc506acf8454d8922ee491Andy Huang    }
12331c38a8247b4583ac1cc506acf8454d8922ee491Andy Huang
12446dfba6160b55a582b344328067e3dafeb881dd9Andy Huang    public boolean isMeasurementValid() {
12546dfba6160b55a582b344328067e3dafeb881dd9Andy Huang        return !mNeedsMeasure;
12646dfba6160b55a582b344328067e3dafeb881dd9Andy Huang    }
12746dfba6160b55a582b344328067e3dafeb881dd9Andy Huang
12846dfba6160b55a582b344328067e3dafeb881dd9Andy Huang    public void markMeasurementValid() {
12946dfba6160b55a582b344328067e3dafeb881dd9Andy Huang        mNeedsMeasure = false;
13046dfba6160b55a582b344328067e3dafeb881dd9Andy Huang    }
13146dfba6160b55a582b344328067e3dafeb881dd9Andy Huang
13246dfba6160b55a582b344328067e3dafeb881dd9Andy Huang    public void invalidateMeasurement() {
13346dfba6160b55a582b344328067e3dafeb881dd9Andy Huang        mNeedsMeasure = true;
13446dfba6160b55a582b344328067e3dafeb881dd9Andy Huang    }
13559e0b18db1bd06cfb74693d7dbb0cb48112a69b1Andy Huang
13659e0b18db1bd06cfb74693d7dbb0cb48112a69b1Andy Huang    public boolean canBecomeSnapHeader() {
13759e0b18db1bd06cfb74693d7dbb0cb48112a69b1Andy Huang        return false;
13859e0b18db1bd06cfb74693d7dbb0cb48112a69b1Andy Huang    }
13959e0b18db1bd06cfb74693d7dbb0cb48112a69b1Andy Huang
14059e0b18db1bd06cfb74693d7dbb0cb48112a69b1Andy Huang    public boolean canPushSnapHeader() {
14159e0b18db1bd06cfb74693d7dbb0cb48112a69b1Andy Huang        return false;
14259e0b18db1bd06cfb74693d7dbb0cb48112a69b1Andy Huang    }
14359e0b18db1bd06cfb74693d7dbb0cb48112a69b1Andy Huang
144014ea4c15d147794789b9c5bf4e243fa08781ad9Andy Huang    public boolean belongsToMessage(ConversationMessage message) {
145014ea4c15d147794789b9c5bf4e243fa08781ad9Andy Huang        return false;
146014ea4c15d147794789b9c5bf4e243fa08781ad9Andy Huang    }
147014ea4c15d147794789b9c5bf4e243fa08781ad9Andy Huang
148014ea4c15d147794789b9c5bf4e243fa08781ad9Andy Huang    public void setMessage(ConversationMessage message) {
149014ea4c15d147794789b9c5bf4e243fa08781ad9Andy Huang    }
150014ea4c15d147794789b9c5bf4e243fa08781ad9Andy Huang
1516b3d0d9ab407c3d8b6bcb73bddbfd23f2513bb83Andy Huang    /**
1526b3d0d9ab407c3d8b6bcb73bddbfd23f2513bb83Andy Huang     * Given a view that is already bound to this item, force the view to re-render the item's
1536b3d0d9ab407c3d8b6bcb73bddbfd23f2513bb83Andy Huang     * current model data. This is typically called after a data model update, to update the
1546b3d0d9ab407c3d8b6bcb73bddbfd23f2513bb83Andy Huang     * affected view in-place.
1556b3d0d9ab407c3d8b6bcb73bddbfd23f2513bb83Andy Huang     */
1566b3d0d9ab407c3d8b6bcb73bddbfd23f2513bb83Andy Huang    public void onModelUpdated(View v) {
1576b3d0d9ab407c3d8b6bcb73bddbfd23f2513bb83Andy Huang    }
1586b3d0d9ab407c3d8b6bcb73bddbfd23f2513bb83Andy Huang
159cee3c90574b48ccaa0f8b9f9341383c231ed41d2Andrew Sapperstein    public void setPosition(int position) {
160cee3c90574b48ccaa0f8b9f9341383c231ed41d2Andrew Sapperstein        mPosition = position;
161cee3c90574b48ccaa0f8b9f9341383c231ed41d2Andrew Sapperstein    }
162cee3c90574b48ccaa0f8b9f9341383c231ed41d2Andrew Sapperstein
163cee3c90574b48ccaa0f8b9f9341383c231ed41d2Andrew Sapperstein    public int getPosition() {
164cee3c90574b48ccaa0f8b9f9341383c231ed41d2Andrew Sapperstein        return mPosition;
165cee3c90574b48ccaa0f8b9f9341383c231ed41d2Andrew Sapperstein    }
166cee3c90574b48ccaa0f8b9f9341383c231ed41d2Andrew Sapperstein
167cee3c90574b48ccaa0f8b9f9341383c231ed41d2Andrew Sapperstein    /**
168cee3c90574b48ccaa0f8b9f9341383c231ed41d2Andrew Sapperstein     * This is a hack. Now that one view can update the
169cee3c90574b48ccaa0f8b9f9341383c231ed41d2Andrew Sapperstein     * state of another view, we need a mechanism when the
170cee3c90574b48ccaa0f8b9f9341383c231ed41d2Andrew Sapperstein     * view's associated item changes to update the state of the
171cee3c90574b48ccaa0f8b9f9341383c231ed41d2Andrew Sapperstein     * view. Typically, classes that override this class should not
172968e014c857439de821cf2590ec6aa44363352d0Andrew Sapperstein     * override this method.<br><br>
173968e014c857439de821cf2590ec6aa44363352d0Andrew Sapperstein     *
174968e014c857439de821cf2590ec6aa44363352d0Andrew Sapperstein     * This method is used by
175cee3c90574b48ccaa0f8b9f9341383c231ed41d2Andrew Sapperstein     * {@link com.android.mail.browse.ConversationViewAdapter.BorderItem}
176cee3c90574b48ccaa0f8b9f9341383c231ed41d2Andrew Sapperstein     * to update the height of the border based on whether the neighboring messages
177968e014c857439de821cf2590ec6aa44363352d0Andrew Sapperstein     * are collapsed or expanded.<br><br>
178968e014c857439de821cf2590ec6aa44363352d0Andrew Sapperstein     *
179968e014c857439de821cf2590ec6aa44363352d0Andrew Sapperstein     * It is also used by {@link com.android.mail.browse.ConversationViewAdapter.MessageHeaderItem}
180968e014c857439de821cf2590ec6aa44363352d0Andrew Sapperstein     * in the case where the snap header is tapped to collapse the message but the
181968e014c857439de821cf2590ec6aa44363352d0Andrew Sapperstein     * message header is still on screen. Since the message header is still on screen,
182968e014c857439de821cf2590ec6aa44363352d0Andrew Sapperstein     * it does not get bound but will get a rebind.<br><br>
183968e014c857439de821cf2590ec6aa44363352d0Andrew Sapperstein     *
184968e014c857439de821cf2590ec6aa44363352d0Andrew Sapperstein     * The only other way to handle this case would be to call
185cee3c90574b48ccaa0f8b9f9341383c231ed41d2Andrew Sapperstein     * {@link com.android.mail.browse.ConversationViewAdapter#notifyDataSetChanged()}
186cee3c90574b48ccaa0f8b9f9341383c231ed41d2Andrew Sapperstein     * but that makes the entire screen flicker since the entire adapter performs
187cee3c90574b48ccaa0f8b9f9341383c231ed41d2Andrew Sapperstein     * a layout of the every item.
188cee3c90574b48ccaa0f8b9f9341383c231ed41d2Andrew Sapperstein     * @param view the view to be re-bound
189cee3c90574b48ccaa0f8b9f9341383c231ed41d2Andrew Sapperstein     */
190cee3c90574b48ccaa0f8b9f9341383c231ed41d2Andrew Sapperstein    public void rebindView(View view) {
191cee3c90574b48ccaa0f8b9f9341383c231ed41d2Andrew Sapperstein        // DO NOTHING
192cee3c90574b48ccaa0f8b9f9341383c231ed41d2Andrew Sapperstein    }
193a7404589b03ac9dd0d07b3f7d0a1ec92ac9acb62Jin Cao
1940b69338a45faa422ccba8faf64c9816c55d33e4aJin Cao    public View getFocusableView() {
1950b69338a45faa422ccba8faf64c9816c55d33e4aJin Cao        // Focus the root view by default
1960b69338a45faa422ccba8faf64c9816c55d33e4aJin Cao        return mRootView;
1970b69338a45faa422ccba8faf64c9816c55d33e4aJin Cao    }
1980b69338a45faa422ccba8faf64c9816c55d33e4aJin Cao
199a7404589b03ac9dd0d07b3f7d0a1ec92ac9acb62Jin Cao    public void registerOnKeyListeners(View... views) {
200a7404589b03ac9dd0d07b3f7d0a1ec92ac9acb62Jin Cao        final View.OnKeyListener listener = getOnKeyListener();
201a7404589b03ac9dd0d07b3f7d0a1ec92ac9acb62Jin Cao        if (listener != null) {
202a7404589b03ac9dd0d07b3f7d0a1ec92ac9acb62Jin Cao            for (View v : views) {
203a7404589b03ac9dd0d07b3f7d0a1ec92ac9acb62Jin Cao                if (v != null) {
204a7404589b03ac9dd0d07b3f7d0a1ec92ac9acb62Jin Cao                    v.setOnKeyListener(listener);
205a7404589b03ac9dd0d07b3f7d0a1ec92ac9acb62Jin Cao                }
206a7404589b03ac9dd0d07b3f7d0a1ec92ac9acb62Jin Cao            }
207a7404589b03ac9dd0d07b3f7d0a1ec92ac9acb62Jin Cao        }
208a7404589b03ac9dd0d07b3f7d0a1ec92ac9acb62Jin Cao    }
20946dfba6160b55a582b344328067e3dafeb881dd9Andy Huang}
210