/* * Copyright (C) 2012 Google Inc. * Licensed to The Android Open Source Project. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.mail.browse; import android.content.Context; import android.view.Gravity; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.Adapter; import android.widget.CursorAdapter; import com.android.mail.browse.ConversationViewAdapter.ConversationViewType; import com.android.mail.ui.ConversationViewFragment; import com.android.mail.utils.LogUtils; public abstract class ConversationOverlayItem { private int mHeight; // in px private int mTop; // in px private boolean mNeedsMeasure; public static final String LOG_TAG = ConversationViewFragment.LAYOUT_TAG; private int mPosition; // The view to focus when this overlay item should be focused. protected View mRootView; /** * @see Adapter#getItemViewType(int) */ public abstract @ConversationViewType int getType(); /** * Inflate and perform one-time initialization on a view for later binding. */ public abstract View createView(Context context, LayoutInflater inflater, ViewGroup parent); /** * @see CursorAdapter#bindView(View, Context, android.database.Cursor) * @param v a view to bind to * @param measureOnly true iff we are binding this view only to measure its height (so items * know they can cut certain corners that do not affect a view's height) */ public abstract void bindView(View v, boolean measureOnly); /** * Returns true if this overlay view is meant to be positioned right on top of the overlay * below. This special positioning allows {@link ConversationContainer} to stack overlays * together even when zoomed into a conversation, when the overlay spacers spread farther * apart. */ public abstract boolean isContiguous(); public View.OnKeyListener getOnKeyListener() { return null; } /** * Returns true if this overlay view is in its expanded state. */ public boolean isExpanded() { return true; } public int getGravity() { return Gravity.BOTTOM; } /** * This method's behavior is critical and requires some 'splainin. *

* Subclasses that return a zero-size height to the {@link ConversationContainer} will * cause the scrolling/recycling logic there to remove any matching view from the container. * The item should switch to returning a non-zero height when its view should re-appear. *

* It's imperative that this method stay in sync with the current height of the HTML spacer * that matches this overlay. */ public int getHeight() { return mHeight; } /** * Set a new height. * * @param h a new height * @return true if the value changed */ public boolean setHeight(int h) { LogUtils.i(LOG_TAG, "IN setHeight=%dpx of overlay item: %s", h, this); if (mHeight != h) { mHeight = h; mNeedsMeasure = true; return true; } return false; } public int getTop() { return mTop; } public void setTop(int top) { mTop = top; } public boolean isMeasurementValid() { return !mNeedsMeasure; } public void markMeasurementValid() { mNeedsMeasure = false; } public void invalidateMeasurement() { mNeedsMeasure = true; } public boolean canBecomeSnapHeader() { return false; } public boolean canPushSnapHeader() { return false; } public boolean belongsToMessage(ConversationMessage message) { return false; } public void setMessage(ConversationMessage message) { } /** * Given a view that is already bound to this item, force the view to re-render the item's * current model data. This is typically called after a data model update, to update the * affected view in-place. */ public void onModelUpdated(View v) { } public void setPosition(int position) { mPosition = position; } public int getPosition() { return mPosition; } /** * This is a hack. Now that one view can update the * state of another view, we need a mechanism when the * view's associated item changes to update the state of the * view. Typically, classes that override this class should not * override this method.

* * This method is used by * {@link com.android.mail.browse.ConversationViewAdapter.BorderItem} * to update the height of the border based on whether the neighboring messages * are collapsed or expanded.

* * It is also used by {@link com.android.mail.browse.ConversationViewAdapter.MessageHeaderItem} * in the case where the snap header is tapped to collapse the message but the * message header is still on screen. Since the message header is still on screen, * it does not get bound but will get a rebind.

* * The only other way to handle this case would be to call * {@link com.android.mail.browse.ConversationViewAdapter#notifyDataSetChanged()} * but that makes the entire screen flicker since the entire adapter performs * a layout of the every item. * @param view the view to be re-bound */ public void rebindView(View view) { // DO NOTHING } public View getFocusableView() { // Focus the root view by default return mRootView; } public void registerOnKeyListeners(View... views) { final View.OnKeyListener listener = getOnKeyListener(); if (listener != null) { for (View v : views) { if (v != null) { v.setOnKeyListener(listener); } } } } }