Restore tag records when re-starting MyTag activity.
[android/platform/packages/apps/Tag.git] / src / com / android / apps / tag / EditTagActivity.java
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.apps.tag;
18
19 import com.android.apps.tag.record.ImageRecord;
20 import com.android.apps.tag.record.ParsedNdefRecord;
21 import com.android.apps.tag.record.RecordEditInfo;
22 import com.android.apps.tag.record.RecordEditInfo.EditCallbacks;
23 import com.android.apps.tag.record.UriRecord;
24 import com.android.apps.tag.record.VCardRecord;
25 import com.google.common.base.Preconditions;
26 import com.google.common.collect.ImmutableSet;
27 import com.google.common.collect.Lists;
28
29 import android.app.Activity;
30 import android.app.Dialog;
31 import android.content.Intent;
32 import android.nfc.NdefMessage;
33 import android.nfc.NdefRecord;
34 import android.os.Bundle;
35 import android.view.LayoutInflater;
36 import android.view.View;
37 import android.view.View.OnClickListener;
38 import android.view.ViewGroup;
39 import java.util.ArrayList;
40 import java.util.Set;
41
42 /**
43  * A base {@link Activity} class for an editor of an {@link NdefMessage} tag.
44  *
45  * The core of the editing is done by various child {@link View}s that differ based on
46  * {@link ParsedNdefRecord} types. Each type of {@link ParsedNdefRecord} can build views to
47  * pick/select a new piece of content, or edit an existing content for the {@link NdefMessage}.
48  */
49 public abstract class EditTagActivity extends Activity implements OnClickListener, EditCallbacks {
50
51     private static final String BUNDLE_KEY_OUTSTANDING_PICK = "outstanding-pick";
52     protected static final int DIALOG_ID_ADD_CONTENT = 0;
53
54     private static final Set<String> SUPPORTED_RECORD_TYPES = ImmutableSet.of(
55         ImageRecord.RECORD_TYPE,
56         UriRecord.RECORD_TYPE,
57         VCardRecord.RECORD_TYPE
58     );
59
60     /**
61      * Records contained in the current message being edited.
62      */
63     protected final ArrayList<RecordEditInfo> mRecords = Lists.newArrayList();
64
65     /**
66      * The container where the subviews for each record are housed.
67      */
68     private ViewGroup mContentRoot;
69
70     /**
71      * Info about an outstanding picking activity to add a new record.
72      */
73     private RecordEditInfo mRecordWithOutstandingPick;
74
75     private LayoutInflater mInflater;
76
77     @Override
78     protected void onCreate(Bundle savedState) {
79         super.onCreate(savedState);
80
81         if (savedState != null) {
82             mRecordWithOutstandingPick = savedState.getParcelable(BUNDLE_KEY_OUTSTANDING_PICK);
83         }
84         mInflater = LayoutInflater.from(this);
85     }
86
87     protected ViewGroup getContentRoot() {
88         if (mContentRoot == null) {
89             mContentRoot = (ViewGroup) findViewById(R.id.content_parent);
90         }
91         return mContentRoot;
92     }
93
94     /**
95      * @return The list of {@link ParsedNdefRecord} types that this editor supports. Subclasses
96      *     may override to filter out specific types.
97      */
98     public Set<String> getSupportedTypes() {
99         return SUPPORTED_RECORD_TYPES;
100     }
101
102     /**
103      * Builds a {@link View} used as an item in a list when picking a new piece of content to add
104      * to the tag.
105      */
106     public View getAddView(ViewGroup parent, String type) {
107         if (ImageRecord.RECORD_TYPE.equals(type)) {
108             return ImageRecord.getAddView(this, mInflater, parent);
109         } else if (UriRecord.RECORD_TYPE.equals(type)) {
110             return UriRecord.getAddView(this, mInflater, parent);
111         } else if (VCardRecord.RECORD_TYPE.equals(type)) {
112             return VCardRecord.getAddView(this, mInflater, parent);
113         }
114         throw new IllegalArgumentException("Not a supported view type");
115     }
116
117     /**
118      * Builds a snapshot of current values as held in the internal state of this editor.
119      */
120     public ArrayList<NdefRecord> getValues() {
121         ArrayList<NdefRecord> result = new ArrayList<NdefRecord>(mRecords.size());
122         for (RecordEditInfo editInfo : mRecords) {
123             result.add(editInfo.getValue());
124         }
125         return result;
126     }
127
128     /**
129      * Builds a {@link View} used as an item in a list when editing content for a tag.
130      */
131     public void addRecord(RecordEditInfo editInfo) {
132         mRecords.add(Preconditions.checkNotNull(editInfo));
133         addViewForRecord(editInfo);
134     }
135
136     /**
137      * Adds a child editor view for a record.
138      */
139     public void addViewForRecord(RecordEditInfo editInfo) {
140         ViewGroup root = getContentRoot();
141         View editView = editInfo.getEditView(this, mInflater, root, this);
142         root.addView(mInflater.inflate(R.layout.tag_divider, root, false));
143         root.addView(editView);
144     }
145
146     protected void rebuildChildViews() {
147         ViewGroup root = getContentRoot();
148         root.removeAllViews();
149         for (RecordEditInfo editInfo : mRecords) {
150             addViewForRecord(editInfo);
151         }
152     }
153
154     @Override
155     protected Dialog onCreateDialog(int id, Bundle args) {
156         if (id == DIALOG_ID_ADD_CONTENT) {
157             return new TagContentSelector(this);
158         }
159         return super.onCreateDialog(id, args);
160     }
161
162     @Override
163     protected void onPrepareDialog(int id, Dialog dialog, Bundle args) {
164         super.onPrepareDialog(id, dialog, args);
165         if (dialog instanceof TagContentSelector) {
166             ((TagContentSelector) dialog).rebuildViews();
167         }
168     }
169
170     /**
171      * Displays a {@link Dialog} to select a new content type to add to the Tag.
172      */
173     protected void showAddContentDialog() {
174         showDialog(DIALOG_ID_ADD_CONTENT);
175     }
176
177     @Override
178     public void startPickForRecord(RecordEditInfo editInfo, Intent intent) {
179         mRecordWithOutstandingPick = editInfo;
180         startActivityForResult(intent, 0);
181     }
182
183     /**
184      * Handles a click to select and add a new content type.
185      */
186     public void onAddContentClick(View target) {
187         Object tag = target.getTag();
188         if ((tag == null) || !(tag instanceof RecordEditInfo)) {
189             return;
190         }
191
192         RecordEditInfo info = (RecordEditInfo) tag;
193         Intent pickIntent = info.getPickIntent();
194         if (pickIntent != null) {
195             startPickForRecord(info, pickIntent);
196         } else {
197             // Does not require an external Activity. Add the edit view directly.
198             addRecord(info);
199         }
200     }
201
202     @Override
203     public void deleteRecord(RecordEditInfo editInfo) {
204         mRecords.remove(editInfo);
205         rebuildChildViews();
206     }
207
208     @Override
209     protected void onActivityResult(int requestCode, int resultCode, Intent data) {
210         if ((resultCode != RESULT_OK) || (data == null)) {
211             mRecordWithOutstandingPick = null;
212             return;
213         }
214         if (mRecordWithOutstandingPick == null) {
215             return;
216         }
217
218         // Handles results from another Activity that picked content to write to a tag.
219         RecordEditInfo recordInfo = mRecordWithOutstandingPick;
220         try {
221             recordInfo.handlePickResult(this, data);
222         } catch (IllegalArgumentException ex) {
223             if (mRecords.contains(recordInfo)) {
224                 deleteRecord(recordInfo);
225             }
226             return;
227         }
228
229         if (mRecords.contains(recordInfo)) {
230             // Editing an existing record. Just rebuild everything.
231             rebuildChildViews();
232
233         } else {
234             // Adding a new record.
235             addRecord(recordInfo);
236         }
237         // TODO: handle errors in picking (e.g. the image is too big, etc).
238
239         mRecordWithOutstandingPick = null;
240     }
241
242     @Override
243     protected void onSaveInstanceState(Bundle outState) {
244         super.onSaveInstanceState(outState);
245
246         if (mRecordWithOutstandingPick != null) {
247             outState.putParcelable(BUNDLE_KEY_OUTSTANDING_PICK, mRecordWithOutstandingPick);
248         }
249     }
250 }