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