Home | History | Annotate | Download | only in ui
      1 /*
      2  * Copyright (C) 2010 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.android.gallery3d.ui;
     18 
     19 import android.graphics.Rect;
     20 
     21 import com.android.gallery3d.app.GalleryActivity;
     22 import com.android.gallery3d.common.Utils;
     23 import com.android.gallery3d.data.MediaItem;
     24 import com.android.gallery3d.data.MediaSet;
     25 import com.android.gallery3d.ui.PositionRepository.Position;
     26 
     27 import java.util.Random;
     28 
     29 public class AlbumSetView extends SlotView {
     30     @SuppressWarnings("unused")
     31     private static final String TAG = "AlbumSetView";
     32     private static final int CACHE_SIZE = 32;
     33     private static final float PHOTO_DISTANCE = 35f;
     34 
     35     private int mVisibleStart;
     36     private int mVisibleEnd;
     37 
     38     private final Random mRandom = new Random();
     39     private final long mSeed = mRandom.nextLong();
     40 
     41     private AlbumSetSlidingWindow mDataWindow;
     42     private final GalleryActivity mActivity;
     43     private final LabelSpec mLabelSpec;
     44 
     45     private SelectionDrawer mSelectionDrawer;
     46 
     47     public static interface Model {
     48         public MediaItem[] getCoverItems(int index);
     49         public MediaSet getMediaSet(int index);
     50         public int size();
     51         public void setActiveWindow(int start, int end);
     52         public void setModelListener(ModelListener listener);
     53     }
     54 
     55     public static interface ModelListener {
     56         public void onWindowContentChanged(int index);
     57         public void onSizeChanged(int size);
     58     }
     59 
     60     public static class AlbumSetItem {
     61         public DisplayItem[] covers;
     62         public DisplayItem labelItem;
     63         public long setDataVersion;
     64     }
     65 
     66     public static class LabelSpec {
     67         public int labelBackgroundHeight;
     68         public int titleOffset;
     69         public int countOffset;
     70         public int titleFontSize;
     71         public int countFontSize;
     72         public int leftMargin;
     73         public int iconSize;
     74     }
     75 
     76     public AlbumSetView(GalleryActivity activity, SelectionDrawer drawer,
     77             SlotView.Spec slotViewSpec, LabelSpec labelSpec) {
     78         super(activity.getAndroidContext());
     79         mActivity = activity;
     80         setSelectionDrawer(drawer);
     81         setSlotSpec(slotViewSpec);
     82         mLabelSpec = labelSpec;
     83     }
     84 
     85     public void setSelectionDrawer(SelectionDrawer drawer) {
     86         mSelectionDrawer = drawer;
     87         if (mDataWindow != null) {
     88             mDataWindow.setSelectionDrawer(drawer);
     89         }
     90     }
     91 
     92     public void setModel(AlbumSetView.Model model) {
     93         if (mDataWindow != null) {
     94             mDataWindow.setListener(null);
     95             setSlotCount(0);
     96             mDataWindow = null;
     97         }
     98         if (model != null) {
     99             mDataWindow = new AlbumSetSlidingWindow(mActivity, mLabelSpec,
    100                     mSelectionDrawer, model, CACHE_SIZE);
    101             mDataWindow.setListener(new MyCacheListener());
    102             setSlotCount(mDataWindow.size());
    103             updateVisibleRange(getVisibleStart(), getVisibleEnd());
    104         }
    105     }
    106 
    107     private void putSlotContent(int slotIndex, AlbumSetItem entry) {
    108         // Get displayItems from mItemsetMap or create them from MediaSet.
    109         Utils.assertTrue(entry != null);
    110         Rect rect = getSlotRect(slotIndex);
    111 
    112         DisplayItem[] items = entry.covers;
    113         mRandom.setSeed(slotIndex ^ mSeed);
    114 
    115         int x = (rect.left + rect.right) / 2;
    116         int y = (rect.top + rect.bottom) / 2;
    117 
    118         Position basePosition = new Position(x, y, 0);
    119 
    120         // Put the cover items in reverse order, so that the first item is on
    121         // top of the rest.
    122         Position position = new Position(x, y, 0f);
    123         putDisplayItem(position, position, entry.labelItem);
    124 
    125         for (int i = 0, n = items.length; i < n; ++i) {
    126             DisplayItem item = items[i];
    127             float dx = 0;
    128             float dy = 0;
    129             float dz = 0f;
    130             float theta = 0;
    131             if (i != 0) {
    132                 dz = i * PHOTO_DISTANCE;
    133             }
    134             position = new Position(x + dx, y + dy, dz);
    135             position.theta = theta;
    136             putDisplayItem(position, basePosition, item);
    137         }
    138 
    139     }
    140 
    141     private void freeSlotContent(int index, AlbumSetItem entry) {
    142         if (entry == null) return;
    143         for (DisplayItem item : entry.covers) {
    144             removeDisplayItem(item);
    145         }
    146         removeDisplayItem(entry.labelItem);
    147     }
    148 
    149     public int size() {
    150         return mDataWindow.size();
    151     }
    152 
    153     @Override
    154     public void onLayoutChanged(int width, int height) {
    155         updateVisibleRange(0, 0);
    156         updateVisibleRange(getVisibleStart(), getVisibleEnd());
    157     }
    158 
    159     @Override
    160     public void onScrollPositionChanged(int position) {
    161         super.onScrollPositionChanged(position);
    162         updateVisibleRange(getVisibleStart(), getVisibleEnd());
    163     }
    164 
    165     private void updateVisibleRange(int start, int end) {
    166         if (start == mVisibleStart && end == mVisibleEnd) {
    167             // we need to set the mDataWindow active range in any case.
    168             mDataWindow.setActiveWindow(start, end);
    169             return;
    170         }
    171         if (start >= mVisibleEnd || mVisibleStart >= end) {
    172             for (int i = mVisibleStart, n = mVisibleEnd; i < n; ++i) {
    173                 freeSlotContent(i, mDataWindow.get(i));
    174             }
    175             mDataWindow.setActiveWindow(start, end);
    176             for (int i = start; i < end; ++i) {
    177                 putSlotContent(i, mDataWindow.get(i));
    178             }
    179         } else {
    180             for (int i = mVisibleStart; i < start; ++i) {
    181                 freeSlotContent(i, mDataWindow.get(i));
    182             }
    183             for (int i = end, n = mVisibleEnd; i < n; ++i) {
    184                 freeSlotContent(i, mDataWindow.get(i));
    185             }
    186             mDataWindow.setActiveWindow(start, end);
    187             for (int i = start, n = mVisibleStart; i < n; ++i) {
    188                 putSlotContent(i, mDataWindow.get(i));
    189             }
    190             for (int i = mVisibleEnd; i < end; ++i) {
    191                 putSlotContent(i, mDataWindow.get(i));
    192             }
    193         }
    194         mVisibleStart = start;
    195         mVisibleEnd = end;
    196 
    197         invalidate();
    198     }
    199 
    200     @Override
    201     protected void render(GLCanvas canvas) {
    202         mSelectionDrawer.prepareDrawing();
    203         super.render(canvas);
    204     }
    205 
    206     private class MyCacheListener implements AlbumSetSlidingWindow.Listener {
    207 
    208         public void onSizeChanged(int size) {
    209             if (setSlotCount(size)) {
    210                 // If the layout parameters are changed, we need reput all items.
    211                 // We keep the visible range at the same center but with size 0.
    212                 // So that we can:
    213                 //     1.) flush all visible items
    214                 //     2.) keep the cached data
    215                 int center = (getVisibleStart() + getVisibleEnd()) / 2;
    216                 updateVisibleRange(center, center);
    217             }
    218             updateVisibleRange(getVisibleStart(), getVisibleEnd());
    219             invalidate();
    220         }
    221 
    222         public void onWindowContentChanged(int slot, AlbumSetItem old, AlbumSetItem update) {
    223             freeSlotContent(slot, old);
    224             putSlotContent(slot, update);
    225             invalidate();
    226         }
    227 
    228         public void onContentInvalidated() {
    229             invalidate();
    230         }
    231     }
    232 
    233     public void pause() {
    234         for (int i = mVisibleStart, n = mVisibleEnd; i < n; ++i) {
    235             freeSlotContent(i, mDataWindow.get(i));
    236         }
    237         mDataWindow.pause();
    238     }
    239 
    240     public void resume() {
    241         mDataWindow.resume();
    242         for (int i = mVisibleStart, n = mVisibleEnd; i < n; ++i) {
    243             putSlotContent(i, mDataWindow.get(i));
    244         }
    245     }
    246 }
    247