1 /* 2 * Copyright (C) 2012 Google Inc. 3 * Licensed to The Android Open Source Project. 4 * 5 * Licensed under the Apache License, Version 2.0 (the "License"); 6 * you may not use this file except in compliance with the License. 7 * You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18 package com.android.mail.browse; 19 20 import android.content.Context; 21 import android.view.Gravity; 22 import android.view.LayoutInflater; 23 import android.view.View; 24 import android.view.ViewGroup; 25 import android.widget.Adapter; 26 import android.widget.CursorAdapter; 27 28 import com.android.mail.ui.ConversationViewFragment; 29 import com.android.mail.utils.LogUtils; 30 31 public abstract class ConversationOverlayItem { 32 private int mHeight; // in px 33 private int mTop; // in px 34 private boolean mNeedsMeasure; 35 36 public static final String LOG_TAG = ConversationViewFragment.LAYOUT_TAG; 37 38 private int mPosition; 39 40 /** 41 * @see Adapter#getItemViewType(int) 42 */ 43 public abstract int getType(); 44 /** 45 * Inflate and perform one-time initialization on a view for later binding. 46 */ 47 public abstract View createView(Context context, LayoutInflater inflater, 48 ViewGroup parent); 49 50 /** 51 * @see CursorAdapter#bindView(View, Context, android.database.Cursor) 52 * @param v a view to bind to 53 * @param measureOnly true iff we are binding this view only to measure its height (so items 54 * know they can cut certain corners that do not affect a view's height) 55 */ 56 public abstract void bindView(View v, boolean measureOnly); 57 /** 58 * Returns true if this overlay view is meant to be positioned right on top of the overlay 59 * below. This special positioning allows {@link ConversationContainer} to stack overlays 60 * together even when zoomed into a conversation, when the overlay spacers spread farther 61 * apart. 62 */ 63 public abstract boolean isContiguous(); 64 65 /** 66 * Returns true if this overlay view is in its expanded state. 67 */ 68 public boolean isExpanded() { 69 return true; 70 } 71 72 public int getGravity() { 73 return Gravity.BOTTOM; 74 } 75 76 /** 77 * This method's behavior is critical and requires some 'splainin. 78 * <p> 79 * Subclasses that return a zero-size height to the {@link ConversationContainer} will 80 * cause the scrolling/recycling logic there to remove any matching view from the container. 81 * The item should switch to returning a non-zero height when its view should re-appear. 82 * <p> 83 * It's imperative that this method stay in sync with the current height of the HTML spacer 84 * that matches this overlay. 85 */ 86 public int getHeight() { 87 return mHeight; 88 } 89 90 /** 91 * Set a new height. 92 * 93 * @param h a new height 94 * @return true if the value changed 95 */ 96 public boolean setHeight(int h) { 97 LogUtils.i(LOG_TAG, "IN setHeight=%dpx of overlay item: %s", h, this); 98 if (mHeight != h) { 99 mHeight = h; 100 mNeedsMeasure = true; 101 return true; 102 } 103 return false; 104 } 105 106 public int getTop() { 107 return mTop; 108 } 109 110 public void setTop(int top) { 111 mTop = top; 112 } 113 114 public boolean isMeasurementValid() { 115 return !mNeedsMeasure; 116 } 117 118 public void markMeasurementValid() { 119 mNeedsMeasure = false; 120 } 121 122 public void invalidateMeasurement() { 123 mNeedsMeasure = true; 124 } 125 126 public boolean canBecomeSnapHeader() { 127 return false; 128 } 129 130 public boolean canPushSnapHeader() { 131 return false; 132 } 133 134 public boolean belongsToMessage(ConversationMessage message) { 135 return false; 136 } 137 138 public void setMessage(ConversationMessage message) { 139 } 140 141 /** 142 * Given a view that is already bound to this item, force the view to re-render the item's 143 * current model data. This is typically called after a data model update, to update the 144 * affected view in-place. 145 */ 146 public void onModelUpdated(View v) { 147 } 148 149 public void setPosition(int position) { 150 mPosition = position; 151 } 152 153 public int getPosition() { 154 return mPosition; 155 } 156 157 /** 158 * This is a hack. Now that one view can update the 159 * state of another view, we need a mechanism when the 160 * view's associated item changes to update the state of the 161 * view. Typically, classes that override this class should not 162 * override this method.<br><br> 163 * 164 * This method is used by 165 * {@link com.android.mail.browse.ConversationViewAdapter.BorderItem} 166 * to update the height of the border based on whether the neighboring messages 167 * are collapsed or expanded.<br><br> 168 * 169 * It is also used by {@link com.android.mail.browse.ConversationViewAdapter.MessageHeaderItem} 170 * in the case where the snap header is tapped to collapse the message but the 171 * message header is still on screen. Since the message header is still on screen, 172 * it does not get bound but will get a rebind.<br><br> 173 * 174 * The only other way to handle this case would be to call 175 * {@link com.android.mail.browse.ConversationViewAdapter#notifyDataSetChanged()} 176 * but that makes the entire screen flicker since the entire adapter performs 177 * a layout of the every item. 178 * @param view the view to be re-bound 179 */ 180 public void rebindView(View view) { 181 // DO NOTHING 182 } 183 } 184