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 */ 16 package com.android.messaging.ui.attachmentchooser; 17 18 import android.content.Context; 19 import android.graphics.Rect; 20 import android.net.Uri; 21 import android.os.Parcel; 22 import android.os.Parcelable; 23 import android.util.AttributeSet; 24 import android.widget.GridView; 25 26 import com.android.messaging.datamodel.data.MessagePartData; 27 import com.android.messaging.ui.attachmentchooser.AttachmentChooserFragment.AttachmentGridAdapter; 28 import com.android.messaging.util.Assert; 29 import com.android.messaging.util.UiUtils; 30 31 import java.util.Collections; 32 import java.util.HashSet; 33 import java.util.Set; 34 35 /** 36 * Displays a grid of attachment previews for the user to choose which to select/unselect 37 */ 38 public class AttachmentGridView extends GridView implements 39 AttachmentGridItemView.HostInterface { 40 public interface AttachmentGridHost { displayPhoto(final Rect viewRect, final Uri photoUri)41 void displayPhoto(final Rect viewRect, final Uri photoUri); updateSelectionCount(final int count)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 AttachmentGridView(final Context context, final AttributeSet attrs)49 public AttachmentGridView(final Context context, final AttributeSet attrs) { 50 super(context, attrs); 51 mUnselectedSet = new HashSet<>(); 52 } 53 setHost(final AttachmentGridHost host)54 public void setHost(final AttachmentGridHost host) { 55 mHost = host; 56 } 57 58 @Override isItemSelected(final MessagePartData attachment)59 public boolean isItemSelected(final MessagePartData attachment) { 60 return !mUnselectedSet.contains(attachment); 61 } 62 63 @Override onItemClicked(final AttachmentGridItemView view, final MessagePartData attachment)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 onItemCheckedChanged(AttachmentGridItemView view, MessagePartData attachment)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 getUnselectedAttachments()84 public Set<MessagePartData> getUnselectedAttachments() { 85 return Collections.unmodifiableSet(mUnselectedSet); 86 } 87 updateSelectionCount()88 private void updateSelectionCount() { 89 final int count = getAdapter().getCount() - mUnselectedSet.size(); 90 Assert.isTrue(count >= 0); 91 mHost.updateSelectionCount(count); 92 } 93 refreshViews()94 private void refreshViews() { 95 if (getAdapter() instanceof AttachmentGridAdapter) { 96 ((AttachmentGridAdapter) getAdapter()).notifyDataSetChanged(); 97 } 98 } 99 100 @Override onSaveInstanceState()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 onRestoreInstanceState(final Parcelable state)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 SavedState(final Parcelable superState)133 SavedState(final Parcelable superState) { 134 super(superState); 135 } 136 SavedState(final Parcel in)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 writeToParcel(final Parcel out, final int flags)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