19f935c7da5a0111f8ee0d2f7c59e6c1695916053Alexander Lucas/*
29f935c7da5a0111f8ee0d2f7c59e6c1695916053Alexander Lucas * Copyright (C) 2011 The Android Open Source Project
39f935c7da5a0111f8ee0d2f7c59e6c1695916053Alexander Lucas *
49f935c7da5a0111f8ee0d2f7c59e6c1695916053Alexander Lucas * Licensed under the Apache License, Version 2.0 (the "License");
59f935c7da5a0111f8ee0d2f7c59e6c1695916053Alexander Lucas * you may not use this file except in compliance with the License.
69f935c7da5a0111f8ee0d2f7c59e6c1695916053Alexander Lucas * You may obtain a copy of the License at
79f935c7da5a0111f8ee0d2f7c59e6c1695916053Alexander Lucas *
89f935c7da5a0111f8ee0d2f7c59e6c1695916053Alexander Lucas *      http://www.apache.org/licenses/LICENSE-2.0
99f935c7da5a0111f8ee0d2f7c59e6c1695916053Alexander Lucas *
109f935c7da5a0111f8ee0d2f7c59e6c1695916053Alexander Lucas * Unless required by applicable law or agreed to in writing, software
119f935c7da5a0111f8ee0d2f7c59e6c1695916053Alexander Lucas * distributed under the License is distributed on an "AS IS" BASIS,
129f935c7da5a0111f8ee0d2f7c59e6c1695916053Alexander Lucas * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
139f935c7da5a0111f8ee0d2f7c59e6c1695916053Alexander Lucas * See the License for the specific language governing permissions and
149f935c7da5a0111f8ee0d2f7c59e6c1695916053Alexander Lucas * limitations under the License.
159f935c7da5a0111f8ee0d2f7c59e6c1695916053Alexander Lucas */
169f935c7da5a0111f8ee0d2f7c59e6c1695916053Alexander Lucas
179f935c7da5a0111f8ee0d2f7c59e6c1695916053Alexander Lucaspackage com.example.android.hcgallery;
189f935c7da5a0111f8ee0d2f7c59e6c1695916053Alexander Lucas
19ddd0d0c656c64b463491d750fadbedf3d682b2a1Scott Mainimport android.app.ActionBar;
20ddd0d0c656c64b463491d750fadbedf3d682b2a1Scott Mainimport android.app.Activity;
21ddd0d0c656c64b463491d750fadbedf3d682b2a1Scott Mainimport android.app.FragmentTransaction;
229f935c7da5a0111f8ee0d2f7c59e6c1695916053Alexander Lucasimport android.app.ListFragment;
239f935c7da5a0111f8ee0d2f7c59e6c1695916053Alexander Lucasimport android.content.ClipData;
24f4f345d0b75c96d92f15a9aba8d58d5d4bec27c6Roman Nurikimport android.content.res.TypedArray;
259f935c7da5a0111f8ee0d2f7c59e6c1695916053Alexander Lucasimport android.graphics.Canvas;
269f935c7da5a0111f8ee0d2f7c59e6c1695916053Alexander Lucasimport android.graphics.Color;
279f935c7da5a0111f8ee0d2f7c59e6c1695916053Alexander Lucasimport android.graphics.drawable.Drawable;
289f935c7da5a0111f8ee0d2f7c59e6c1695916053Alexander Lucasimport android.os.Bundle;
299f935c7da5a0111f8ee0d2f7c59e6c1695916053Alexander Lucasimport android.view.View;
30ddd0d0c656c64b463491d750fadbedf3d682b2a1Scott Mainimport android.view.ViewTreeObserver;
319f935c7da5a0111f8ee0d2f7c59e6c1695916053Alexander Lucasimport android.widget.AdapterView;
32ddd0d0c656c64b463491d750fadbedf3d682b2a1Scott Mainimport android.widget.AdapterView.OnItemLongClickListener;
339f935c7da5a0111f8ee0d2f7c59e6c1695916053Alexander Lucasimport android.widget.ArrayAdapter;
34ddd0d0c656c64b463491d750fadbedf3d682b2a1Scott Mainimport android.widget.FrameLayout;
35ddd0d0c656c64b463491d750fadbedf3d682b2a1Scott Mainimport android.widget.FrameLayout.LayoutParams;
369f935c7da5a0111f8ee0d2f7c59e6c1695916053Alexander Lucasimport android.widget.ListView;
379f935c7da5a0111f8ee0d2f7c59e6c1695916053Alexander Lucasimport android.widget.TextView;
389f935c7da5a0111f8ee0d2f7c59e6c1695916053Alexander Lucas
39ddd0d0c656c64b463491d750fadbedf3d682b2a1Scott Main/**
40ddd0d0c656c64b463491d750fadbedf3d682b2a1Scott Main * Fragment that shows the list of images
41ddd0d0c656c64b463491d750fadbedf3d682b2a1Scott Main * As an extension of ListFragment, this fragment uses a default layout
42ddd0d0c656c64b463491d750fadbedf3d682b2a1Scott Main * that includes a single ListView, which you can acquire with getListView()
43ddd0d0c656c64b463491d750fadbedf3d682b2a1Scott Main * When running on a screen size smaller than "large", this fragment appears alone
44ddd0d0c656c64b463491d750fadbedf3d682b2a1Scott Main * in MainActivity. In this case, selecting a list item opens the ContentActivity,
45ddd0d0c656c64b463491d750fadbedf3d682b2a1Scott Main * which likewise holds only the ContentFragment.
46ddd0d0c656c64b463491d750fadbedf3d682b2a1Scott Main */
47ddd0d0c656c64b463491d750fadbedf3d682b2a1Scott Mainpublic class TitlesFragment extends ListFragment implements ActionBar.TabListener {
48ddd0d0c656c64b463491d750fadbedf3d682b2a1Scott Main    OnItemSelectedListener mListener;
499f935c7da5a0111f8ee0d2f7c59e6c1695916053Alexander Lucas    private int mCategory = 0;
509f935c7da5a0111f8ee0d2f7c59e6c1695916053Alexander Lucas    private int mCurPosition = 0;
51ddd0d0c656c64b463491d750fadbedf3d682b2a1Scott Main    private boolean mDualFragments = false;
52ddd0d0c656c64b463491d750fadbedf3d682b2a1Scott Main
53ddd0d0c656c64b463491d750fadbedf3d682b2a1Scott Main    /** Container Activity must implement this interface and we ensure
54ddd0d0c656c64b463491d750fadbedf3d682b2a1Scott Main     * that it does during the onAttach() callback
55ddd0d0c656c64b463491d750fadbedf3d682b2a1Scott Main     */
56ddd0d0c656c64b463491d750fadbedf3d682b2a1Scott Main    public interface OnItemSelectedListener {
57ddd0d0c656c64b463491d750fadbedf3d682b2a1Scott Main        public void onItemSelected(int category, int position);
58ddd0d0c656c64b463491d750fadbedf3d682b2a1Scott Main    }
599f935c7da5a0111f8ee0d2f7c59e6c1695916053Alexander Lucas
609f935c7da5a0111f8ee0d2f7c59e6c1695916053Alexander Lucas    @Override
61ddd0d0c656c64b463491d750fadbedf3d682b2a1Scott Main    public void onAttach(Activity activity) {
62ddd0d0c656c64b463491d750fadbedf3d682b2a1Scott Main        super.onAttach(activity);
63ddd0d0c656c64b463491d750fadbedf3d682b2a1Scott Main        // Check that the container activity has implemented the callback interface
64ddd0d0c656c64b463491d750fadbedf3d682b2a1Scott Main        try {
65ddd0d0c656c64b463491d750fadbedf3d682b2a1Scott Main            mListener = (OnItemSelectedListener) activity;
66ddd0d0c656c64b463491d750fadbedf3d682b2a1Scott Main        } catch (ClassCastException e) {
67ddd0d0c656c64b463491d750fadbedf3d682b2a1Scott Main            throw new ClassCastException(activity.toString()
68ddd0d0c656c64b463491d750fadbedf3d682b2a1Scott Main                    + " must implement OnItemSelectedListener");
69ddd0d0c656c64b463491d750fadbedf3d682b2a1Scott Main        }
70ddd0d0c656c64b463491d750fadbedf3d682b2a1Scott Main    }
71ddd0d0c656c64b463491d750fadbedf3d682b2a1Scott Main
72ddd0d0c656c64b463491d750fadbedf3d682b2a1Scott Main    /** This is where we perform setup for the fragment that's either
73ddd0d0c656c64b463491d750fadbedf3d682b2a1Scott Main     * not related to the fragment's layout or must be done after the layout is drawn.
74ddd0d0c656c64b463491d750fadbedf3d682b2a1Scott Main     * Notice that this fragment does not implement onCreateView(), because it extends
75ddd0d0c656c64b463491d750fadbedf3d682b2a1Scott Main     * ListFragment, which includes a ListView as the root view by default, so there's
76ddd0d0c656c64b463491d750fadbedf3d682b2a1Scott Main     * no need to set up the layout.
77ddd0d0c656c64b463491d750fadbedf3d682b2a1Scott Main     */
78ddd0d0c656c64b463491d750fadbedf3d682b2a1Scott Main    @Override
799f935c7da5a0111f8ee0d2f7c59e6c1695916053Alexander Lucas    public void onActivityCreated(Bundle savedInstanceState) {
809f935c7da5a0111f8ee0d2f7c59e6c1695916053Alexander Lucas        super.onActivityCreated(savedInstanceState);
819f935c7da5a0111f8ee0d2f7c59e6c1695916053Alexander Lucas
82ddd0d0c656c64b463491d750fadbedf3d682b2a1Scott Main        ContentFragment frag = (ContentFragment) getFragmentManager()
83ddd0d0c656c64b463491d750fadbedf3d682b2a1Scott Main                .findFragmentById(R.id.content_frag);
84ddd0d0c656c64b463491d750fadbedf3d682b2a1Scott Main        if (frag != null) mDualFragments = true;
85ddd0d0c656c64b463491d750fadbedf3d682b2a1Scott Main
86ddd0d0c656c64b463491d750fadbedf3d682b2a1Scott Main        ActionBar bar = getActivity().getActionBar();
87ddd0d0c656c64b463491d750fadbedf3d682b2a1Scott Main        bar.setDisplayHomeAsUpEnabled(false);
88ddd0d0c656c64b463491d750fadbedf3d682b2a1Scott Main        bar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
89ddd0d0c656c64b463491d750fadbedf3d682b2a1Scott Main
90ddd0d0c656c64b463491d750fadbedf3d682b2a1Scott Main        // Must call in order to get callback to onCreateOptionsMenu()
91ddd0d0c656c64b463491d750fadbedf3d682b2a1Scott Main        setHasOptionsMenu(true);
92ddd0d0c656c64b463491d750fadbedf3d682b2a1Scott Main
93ddd0d0c656c64b463491d750fadbedf3d682b2a1Scott Main        Directory.initializeDirectory();
94ddd0d0c656c64b463491d750fadbedf3d682b2a1Scott Main        for (int i = 0; i < Directory.getCategoryCount(); i++) {
95ddd0d0c656c64b463491d750fadbedf3d682b2a1Scott Main            bar.addTab(bar.newTab().setText(Directory.getCategory(i).getName())
96ddd0d0c656c64b463491d750fadbedf3d682b2a1Scott Main                    .setTabListener(this));
97ddd0d0c656c64b463491d750fadbedf3d682b2a1Scott Main        }
98ddd0d0c656c64b463491d750fadbedf3d682b2a1Scott Main
999f935c7da5a0111f8ee0d2f7c59e6c1695916053Alexander Lucas        //Current position should survive screen rotations.
1009f935c7da5a0111f8ee0d2f7c59e6c1695916053Alexander Lucas        if (savedInstanceState != null) {
1019f935c7da5a0111f8ee0d2f7c59e6c1695916053Alexander Lucas            mCategory = savedInstanceState.getInt("category");
1029f935c7da5a0111f8ee0d2f7c59e6c1695916053Alexander Lucas            mCurPosition = savedInstanceState.getInt("listPosition");
103ddd0d0c656c64b463491d750fadbedf3d682b2a1Scott Main            bar.selectTab(bar.getTabAt(mCategory));
1049f935c7da5a0111f8ee0d2f7c59e6c1695916053Alexander Lucas        }
1059f935c7da5a0111f8ee0d2f7c59e6c1695916053Alexander Lucas
1069f935c7da5a0111f8ee0d2f7c59e6c1695916053Alexander Lucas        populateTitles(mCategory);
1079f935c7da5a0111f8ee0d2f7c59e6c1695916053Alexander Lucas        ListView lv = getListView();
108ddd0d0c656c64b463491d750fadbedf3d682b2a1Scott Main        lv.setCacheColorHint(Color.TRANSPARENT); // Improves scrolling performance
109ddd0d0c656c64b463491d750fadbedf3d682b2a1Scott Main
110ddd0d0c656c64b463491d750fadbedf3d682b2a1Scott Main        if (mDualFragments) {
111ddd0d0c656c64b463491d750fadbedf3d682b2a1Scott Main            // Highlight the currently selected item
112ddd0d0c656c64b463491d750fadbedf3d682b2a1Scott Main            lv.setChoiceMode(ListView.CHOICE_MODE_SINGLE);
113ddd0d0c656c64b463491d750fadbedf3d682b2a1Scott Main            // Enable drag and dropping
114ddd0d0c656c64b463491d750fadbedf3d682b2a1Scott Main            lv.setOnItemLongClickListener(new OnItemLongClickListener() {
115ddd0d0c656c64b463491d750fadbedf3d682b2a1Scott Main                public boolean onItemLongClick(AdapterView<?> av, View v, int pos, long id) {
116ddd0d0c656c64b463491d750fadbedf3d682b2a1Scott Main                    final String title = (String) ((TextView) v).getText();
117ddd0d0c656c64b463491d750fadbedf3d682b2a1Scott Main
118ddd0d0c656c64b463491d750fadbedf3d682b2a1Scott Main                    // Set up clip data with the category||entry_id format.
119ddd0d0c656c64b463491d750fadbedf3d682b2a1Scott Main                    final String textData = String.format("%d||%d", mCategory, pos);
120ddd0d0c656c64b463491d750fadbedf3d682b2a1Scott Main                    ClipData data = ClipData.newPlainText(title, textData);
121ddd0d0c656c64b463491d750fadbedf3d682b2a1Scott Main                    v.startDrag(data, new MyDragShadowBuilder(v), null, 0);
122ddd0d0c656c64b463491d750fadbedf3d682b2a1Scott Main                    return true;
123ddd0d0c656c64b463491d750fadbedf3d682b2a1Scott Main                }
124ddd0d0c656c64b463491d750fadbedf3d682b2a1Scott Main            });
125ddd0d0c656c64b463491d750fadbedf3d682b2a1Scott Main        }
126ddd0d0c656c64b463491d750fadbedf3d682b2a1Scott Main
127ddd0d0c656c64b463491d750fadbedf3d682b2a1Scott Main        // If showing both fragments, select the appropriate list item by default
128ddd0d0c656c64b463491d750fadbedf3d682b2a1Scott Main        if (mDualFragments) selectPosition(mCurPosition);
129ddd0d0c656c64b463491d750fadbedf3d682b2a1Scott Main
130ddd0d0c656c64b463491d750fadbedf3d682b2a1Scott Main        // Attach a GlobalLayoutListener so that we get a callback when the layout
131ddd0d0c656c64b463491d750fadbedf3d682b2a1Scott Main        // has finished drawing. This is necessary so that we can apply top-margin
132ddd0d0c656c64b463491d750fadbedf3d682b2a1Scott Main        // to the ListView in order to dodge the ActionBar. Ordinarily, that's not
133ddd0d0c656c64b463491d750fadbedf3d682b2a1Scott Main        // necessary, but we've set the ActionBar to "overlay" mode using our theme,
134ddd0d0c656c64b463491d750fadbedf3d682b2a1Scott Main        // so the layout does not account for the action bar position on its own.
135ddd0d0c656c64b463491d750fadbedf3d682b2a1Scott Main        ViewTreeObserver observer = getListView().getViewTreeObserver();
136ddd0d0c656c64b463491d750fadbedf3d682b2a1Scott Main        observer.addOnGlobalLayoutListener(layoutListener);
137ddd0d0c656c64b463491d750fadbedf3d682b2a1Scott Main    }
138f4f345d0b75c96d92f15a9aba8d58d5d4bec27c6Roman Nurik
139ddd0d0c656c64b463491d750fadbedf3d682b2a1Scott Main    @Override
140ddd0d0c656c64b463491d750fadbedf3d682b2a1Scott Main    public void onDestroyView() {
141ddd0d0c656c64b463491d750fadbedf3d682b2a1Scott Main      super.onDestroyView();
142ddd0d0c656c64b463491d750fadbedf3d682b2a1Scott Main      // Always detach ViewTreeObserver listeners when the view tears down
143ddd0d0c656c64b463491d750fadbedf3d682b2a1Scott Main      getListView().getViewTreeObserver().removeGlobalOnLayoutListener(layoutListener);
1449f935c7da5a0111f8ee0d2f7c59e6c1695916053Alexander Lucas    }
1459f935c7da5a0111f8ee0d2f7c59e6c1695916053Alexander Lucas
146ddd0d0c656c64b463491d750fadbedf3d682b2a1Scott Main    /** Attaches an adapter to the fragment's ListView to populate it with items */
147ddd0d0c656c64b463491d750fadbedf3d682b2a1Scott Main    public void populateTitles(int category) {
148ddd0d0c656c64b463491d750fadbedf3d682b2a1Scott Main        DirectoryCategory cat = Directory.getCategory(category);
149ddd0d0c656c64b463491d750fadbedf3d682b2a1Scott Main        String[] items = new String[cat.getEntryCount()];
150ddd0d0c656c64b463491d750fadbedf3d682b2a1Scott Main        for (int i = 0; i < cat.getEntryCount(); i++)
151ddd0d0c656c64b463491d750fadbedf3d682b2a1Scott Main            items[i] = cat.getEntry(i).getName();
152ddd0d0c656c64b463491d750fadbedf3d682b2a1Scott Main        // Convenience method to attach an adapter to ListFragment's ListView
153ddd0d0c656c64b463491d750fadbedf3d682b2a1Scott Main        setListAdapter(new ArrayAdapter<String>(getActivity(),
154ddd0d0c656c64b463491d750fadbedf3d682b2a1Scott Main                R.layout.title_list_item, items));
155ddd0d0c656c64b463491d750fadbedf3d682b2a1Scott Main        mCategory = category;
156ddd0d0c656c64b463491d750fadbedf3d682b2a1Scott Main    }
157ddd0d0c656c64b463491d750fadbedf3d682b2a1Scott Main
158ddd0d0c656c64b463491d750fadbedf3d682b2a1Scott Main    @Override
159ddd0d0c656c64b463491d750fadbedf3d682b2a1Scott Main    public void onListItemClick(ListView l, View v, int position, long id) {
160ddd0d0c656c64b463491d750fadbedf3d682b2a1Scott Main        // Send the event to the host activity via OnItemSelectedListener callback
161ddd0d0c656c64b463491d750fadbedf3d682b2a1Scott Main        mListener.onItemSelected(mCategory, position);
162ddd0d0c656c64b463491d750fadbedf3d682b2a1Scott Main        mCurPosition = position;
163ddd0d0c656c64b463491d750fadbedf3d682b2a1Scott Main    }
164ddd0d0c656c64b463491d750fadbedf3d682b2a1Scott Main
165ddd0d0c656c64b463491d750fadbedf3d682b2a1Scott Main    /** Called to select an item from the listview */
166ddd0d0c656c64b463491d750fadbedf3d682b2a1Scott Main    public void selectPosition(int position) {
167ddd0d0c656c64b463491d750fadbedf3d682b2a1Scott Main        // Only if we're showing both fragments should the item be "highlighted"
168ddd0d0c656c64b463491d750fadbedf3d682b2a1Scott Main        if (mDualFragments) {
169ddd0d0c656c64b463491d750fadbedf3d682b2a1Scott Main            ListView lv = getListView();
170ddd0d0c656c64b463491d750fadbedf3d682b2a1Scott Main            lv.setItemChecked(position, true);
171ddd0d0c656c64b463491d750fadbedf3d682b2a1Scott Main        }
172ddd0d0c656c64b463491d750fadbedf3d682b2a1Scott Main        // Calls the parent activity's implementation of the OnItemSelectedListener
173ddd0d0c656c64b463491d750fadbedf3d682b2a1Scott Main        // so the activity can pass the event to the sibling fragment as appropriate
174ddd0d0c656c64b463491d750fadbedf3d682b2a1Scott Main        mListener.onItemSelected(mCategory, position);
175ddd0d0c656c64b463491d750fadbedf3d682b2a1Scott Main    }
176ddd0d0c656c64b463491d750fadbedf3d682b2a1Scott Main
177ddd0d0c656c64b463491d750fadbedf3d682b2a1Scott Main    @Override
178ddd0d0c656c64b463491d750fadbedf3d682b2a1Scott Main    public void onSaveInstanceState (Bundle outState) {
179ddd0d0c656c64b463491d750fadbedf3d682b2a1Scott Main        super.onSaveInstanceState(outState);
180ddd0d0c656c64b463491d750fadbedf3d682b2a1Scott Main        outState.putInt("listPosition", mCurPosition);
181ddd0d0c656c64b463491d750fadbedf3d682b2a1Scott Main        outState.putInt("category", mCategory);
182ddd0d0c656c64b463491d750fadbedf3d682b2a1Scott Main    }
183ddd0d0c656c64b463491d750fadbedf3d682b2a1Scott Main
184ddd0d0c656c64b463491d750fadbedf3d682b2a1Scott Main    /** This defines how the draggable list items appear during a drag event */
185f4f345d0b75c96d92f15a9aba8d58d5d4bec27c6Roman Nurik    private class MyDragShadowBuilder extends View.DragShadowBuilder {
186f4f345d0b75c96d92f15a9aba8d58d5d4bec27c6Roman Nurik        private Drawable mShadow;
187f4f345d0b75c96d92f15a9aba8d58d5d4bec27c6Roman Nurik
188f4f345d0b75c96d92f15a9aba8d58d5d4bec27c6Roman Nurik        public MyDragShadowBuilder(View v) {
1899f935c7da5a0111f8ee0d2f7c59e6c1695916053Alexander Lucas            super(v);
190f4f345d0b75c96d92f15a9aba8d58d5d4bec27c6Roman Nurik
191f4f345d0b75c96d92f15a9aba8d58d5d4bec27c6Roman Nurik            final TypedArray a = v.getContext().obtainStyledAttributes(R.styleable.AppTheme);
192f4f345d0b75c96d92f15a9aba8d58d5d4bec27c6Roman Nurik            mShadow = a.getDrawable(R.styleable.AppTheme_listDragShadowBackground);
193f4f345d0b75c96d92f15a9aba8d58d5d4bec27c6Roman Nurik            mShadow.setCallback(v);
194821736e1fb70be2c827c9e6a35a7739762523897Alexander Lucas            mShadow.setBounds(0, 0, v.getWidth(), v.getHeight());
195f4f345d0b75c96d92f15a9aba8d58d5d4bec27c6Roman Nurik            a.recycle();
1969f935c7da5a0111f8ee0d2f7c59e6c1695916053Alexander Lucas        }
1979f935c7da5a0111f8ee0d2f7c59e6c1695916053Alexander Lucas
1989f935c7da5a0111f8ee0d2f7c59e6c1695916053Alexander Lucas        @Override
1999f935c7da5a0111f8ee0d2f7c59e6c1695916053Alexander Lucas        public void onDrawShadow(Canvas canvas) {
200821736e1fb70be2c827c9e6a35a7739762523897Alexander Lucas            super.onDrawShadow(canvas);
201821736e1fb70be2c827c9e6a35a7739762523897Alexander Lucas            mShadow.draw(canvas);
202f4f345d0b75c96d92f15a9aba8d58d5d4bec27c6Roman Nurik            getView().draw(canvas);
2039f935c7da5a0111f8ee0d2f7c59e6c1695916053Alexander Lucas        }
2049f935c7da5a0111f8ee0d2f7c59e6c1695916053Alexander Lucas    }
2059f935c7da5a0111f8ee0d2f7c59e6c1695916053Alexander Lucas
206ddd0d0c656c64b463491d750fadbedf3d682b2a1Scott Main    // Because the fragment doesn't have a reliable callback to notify us when
207ddd0d0c656c64b463491d750fadbedf3d682b2a1Scott Main    // the activity's layout is completely drawn, this OnGlobalLayoutListener provides
208ddd0d0c656c64b463491d750fadbedf3d682b2a1Scott Main    // the necessary callback so we can add top-margin to the ListView in order to dodge
209ddd0d0c656c64b463491d750fadbedf3d682b2a1Scott Main    // the ActionBar. Which is necessary because the ActionBar is in overlay mode, meaning
210ddd0d0c656c64b463491d750fadbedf3d682b2a1Scott Main    // that it will ordinarily sit on top of the activity layout as a top layer and
211ddd0d0c656c64b463491d750fadbedf3d682b2a1Scott Main    // the ActionBar height can vary. Specifically, when on a small/normal size screen,
212ddd0d0c656c64b463491d750fadbedf3d682b2a1Scott Main    // the action bar tabs appear in a second row, making the action bar twice as tall.
213ddd0d0c656c64b463491d750fadbedf3d682b2a1Scott Main    ViewTreeObserver.OnGlobalLayoutListener layoutListener = new ViewTreeObserver.OnGlobalLayoutListener() {
214ddd0d0c656c64b463491d750fadbedf3d682b2a1Scott Main        @Override
215ddd0d0c656c64b463491d750fadbedf3d682b2a1Scott Main        public void onGlobalLayout() {
216ddd0d0c656c64b463491d750fadbedf3d682b2a1Scott Main            int barHeight = getActivity().getActionBar().getHeight();
217ddd0d0c656c64b463491d750fadbedf3d682b2a1Scott Main            ListView listView = getListView();
218ddd0d0c656c64b463491d750fadbedf3d682b2a1Scott Main            FrameLayout.LayoutParams params = (LayoutParams) listView.getLayoutParams();
219ddd0d0c656c64b463491d750fadbedf3d682b2a1Scott Main            // The list view top-margin should always match the action bar height
220ddd0d0c656c64b463491d750fadbedf3d682b2a1Scott Main            if (params.topMargin != barHeight) {
221ddd0d0c656c64b463491d750fadbedf3d682b2a1Scott Main                params.topMargin = barHeight;
222ddd0d0c656c64b463491d750fadbedf3d682b2a1Scott Main                listView.setLayoutParams(params);
223ddd0d0c656c64b463491d750fadbedf3d682b2a1Scott Main            }
224ddd0d0c656c64b463491d750fadbedf3d682b2a1Scott Main            // The action bar doesn't update its height when hidden, so make top-margin zero
225ddd0d0c656c64b463491d750fadbedf3d682b2a1Scott Main            if (!getActivity().getActionBar().isShowing()) {
226ddd0d0c656c64b463491d750fadbedf3d682b2a1Scott Main              params.topMargin = 0;
227ddd0d0c656c64b463491d750fadbedf3d682b2a1Scott Main              listView.setLayoutParams(params);
228ddd0d0c656c64b463491d750fadbedf3d682b2a1Scott Main            }
229ddd0d0c656c64b463491d750fadbedf3d682b2a1Scott Main        }
230ddd0d0c656c64b463491d750fadbedf3d682b2a1Scott Main    };
2319f935c7da5a0111f8ee0d2f7c59e6c1695916053Alexander Lucas
2329f935c7da5a0111f8ee0d2f7c59e6c1695916053Alexander Lucas
233ddd0d0c656c64b463491d750fadbedf3d682b2a1Scott Main    /* The following are callbacks implemented for the ActionBar.TabListener,
234ddd0d0c656c64b463491d750fadbedf3d682b2a1Scott Main     * which this fragment implements to handle events when tabs are selected.
235ddd0d0c656c64b463491d750fadbedf3d682b2a1Scott Main     */
236ddd0d0c656c64b463491d750fadbedf3d682b2a1Scott Main
237ddd0d0c656c64b463491d750fadbedf3d682b2a1Scott Main    public void onTabSelected(ActionBar.Tab tab, FragmentTransaction ft) {
238ddd0d0c656c64b463491d750fadbedf3d682b2a1Scott Main        TitlesFragment titleFrag = (TitlesFragment) getFragmentManager()
239ddd0d0c656c64b463491d750fadbedf3d682b2a1Scott Main                .findFragmentById(R.id.titles_frag);
240ddd0d0c656c64b463491d750fadbedf3d682b2a1Scott Main        titleFrag.populateTitles(tab.getPosition());
241ddd0d0c656c64b463491d750fadbedf3d682b2a1Scott Main
242ddd0d0c656c64b463491d750fadbedf3d682b2a1Scott Main        if (mDualFragments) {
243ddd0d0c656c64b463491d750fadbedf3d682b2a1Scott Main            titleFrag.selectPosition(0);
244ddd0d0c656c64b463491d750fadbedf3d682b2a1Scott Main        }
2459f935c7da5a0111f8ee0d2f7c59e6c1695916053Alexander Lucas    }
2469f935c7da5a0111f8ee0d2f7c59e6c1695916053Alexander Lucas
247ddd0d0c656c64b463491d750fadbedf3d682b2a1Scott Main    /* These must be implemented, but we don't use them */
248ddd0d0c656c64b463491d750fadbedf3d682b2a1Scott Main
249ddd0d0c656c64b463491d750fadbedf3d682b2a1Scott Main    public void onTabUnselected(ActionBar.Tab tab, FragmentTransaction ft) {
2509f935c7da5a0111f8ee0d2f7c59e6c1695916053Alexander Lucas    }
2519f935c7da5a0111f8ee0d2f7c59e6c1695916053Alexander Lucas
252ddd0d0c656c64b463491d750fadbedf3d682b2a1Scott Main    public void onTabReselected(ActionBar.Tab tab, FragmentTransaction ft) {
2539f935c7da5a0111f8ee0d2f7c59e6c1695916053Alexander Lucas    }
254ddd0d0c656c64b463491d750fadbedf3d682b2a1Scott Main
2559f935c7da5a0111f8ee0d2f7c59e6c1695916053Alexander Lucas}
256