AttachmentGridView.java revision 461a34b466cb4b13dbbc2ec6330b31e217b2ac4e
1/*
2 * Copyright (C) 2015 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 */
16package com.android.messaging.ui.attachmentchooser;
17
18import android.content.Context;
19import android.graphics.Rect;
20import android.net.Uri;
21import android.os.Parcel;
22import android.os.Parcelable;
23import android.util.AttributeSet;
24import android.widget.GridView;
25
26import com.android.messaging.datamodel.data.MessagePartData;
27import com.android.messaging.ui.attachmentchooser.AttachmentChooserFragment.AttachmentGridAdapter;
28import com.android.messaging.util.Assert;
29import com.android.messaging.util.UiUtils;
30
31import java.util.Collections;
32import java.util.HashSet;
33import java.util.Set;
34
35/**
36 * Displays a grid of attachment previews for the user to choose which to select/unselect
37 */
38public class AttachmentGridView extends GridView implements
39        AttachmentGridItemView.HostInterface {
40    public interface AttachmentGridHost {
41        void displayPhoto(final Rect viewRect, final Uri photoUri);
42        void updateSelectionCount(final int count);
43    }
44
45    // By default everything is selected so only need to keep track of the unselected set.
46    private final Set<MessagePartData> mUnselectedSet;
47    private AttachmentGridHost mHost;
48
49    public AttachmentGridView(final Context context, final AttributeSet attrs) {
50        super(context, attrs);
51        mUnselectedSet = new HashSet<>();
52    }
53
54    public void setHost(final AttachmentGridHost host) {
55        mHost = host;
56    }
57
58    @Override
59    public boolean isItemSelected(final MessagePartData attachment) {
60        return !mUnselectedSet.contains(attachment);
61    }
62
63    @Override
64    public void onItemClicked(final AttachmentGridItemView view, final MessagePartData attachment) {
65        // If the item is an image, show the photo viewer. All the other types (video, audio,
66        // vcard) have internal click handling for showing previews so we don't need to handle them
67        if (attachment.isImage()) {
68            mHost.displayPhoto(UiUtils.getMeasuredBoundsOnScreen(view), attachment.getContentUri());
69        }
70    }
71
72    @Override
73    public void onItemCheckedChanged(AttachmentGridItemView view, MessagePartData attachment) {
74        // Toggle selection.
75        if (isItemSelected(attachment)) {
76            mUnselectedSet.add(attachment);
77        } else {
78            mUnselectedSet.remove(attachment);
79        }
80        view.updateSelectedState();
81        updateSelectionCount();
82    }
83
84    public Set<MessagePartData> getUnselectedAttachments() {
85        return Collections.unmodifiableSet(mUnselectedSet);
86    }
87
88    private void updateSelectionCount() {
89        final int count = getAdapter().getCount() - mUnselectedSet.size();
90        Assert.isTrue(count >= 0);
91        mHost.updateSelectionCount(count);
92    }
93
94    private void refreshViews() {
95        if (getAdapter() instanceof AttachmentGridAdapter) {
96            ((AttachmentGridAdapter) getAdapter()).notifyDataSetChanged();
97        }
98    }
99
100    @Override
101    public Parcelable onSaveInstanceState() {
102        final Parcelable superState = super.onSaveInstanceState();
103        final SavedState savedState = new SavedState(superState);
104        savedState.unselectedParts = mUnselectedSet
105                .toArray(new MessagePartData[mUnselectedSet.size()]);
106        return savedState;
107    }
108
109    @Override
110    public void onRestoreInstanceState(final Parcelable state) {
111        if (!(state instanceof SavedState)) {
112            super.onRestoreInstanceState(state);
113            return;
114        }
115
116        final SavedState savedState = (SavedState) state;
117        super.onRestoreInstanceState(savedState.getSuperState());
118        mUnselectedSet.clear();
119        for (int i = 0; i < savedState.unselectedParts.length; i++) {
120            final MessagePartData unselectedPart = savedState.unselectedParts[i];
121            mUnselectedSet.add(unselectedPart);
122        }
123        refreshViews();
124    }
125
126    /**
127     * Persists the item selection state to saved instance state so we can restore on activity
128     * recreation
129     */
130    public static class SavedState extends BaseSavedState {
131        MessagePartData[] unselectedParts;
132
133        SavedState(final Parcelable superState) {
134            super(superState);
135        }
136
137        private SavedState(final Parcel in) {
138            super(in);
139
140            // Read parts
141            final int partCount = in.readInt();
142            unselectedParts = new MessagePartData[partCount];
143            for (int i = 0; i < partCount; i++) {
144                unselectedParts[i] = ((MessagePartData) in.readParcelable(
145                        MessagePartData.class.getClassLoader()));
146            }
147        }
148
149        @Override
150        public void writeToParcel(final Parcel out, final int flags) {
151            super.writeToParcel(out, flags);
152
153            // Write parts
154            out.writeInt(unselectedParts.length);
155            for (final MessagePartData image : unselectedParts) {
156                out.writeParcelable(image, flags);
157            }
158        }
159
160        public static final Parcelable.Creator<SavedState> CREATOR =
161                new Parcelable.Creator<SavedState>() {
162            @Override
163            public SavedState createFromParcel(final Parcel in) {
164                return new SavedState(in);
165            }
166            @Override
167            public SavedState[] newArray(final int size) {
168                return new SavedState[size];
169            }
170        };
171    }
172}
173