blob: f4fcf382d2f6040bd116ad23aee739ec8a81a868 [file] [log] [blame]
Jeff Hamilton79495342010-10-18 13:13:10 -05001/*
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
17package com.android.apps.tag;
18
19import com.android.apps.tag.message.NdefMessageParser;
20import com.android.apps.tag.message.ParsedNdefMessage;
Jeff Hamilton0215c982010-10-18 17:27:21 -050021import com.android.apps.tag.provider.TagContract.NdefMessages;
Jeff Hamilton79495342010-10-18 13:13:10 -050022import com.android.apps.tag.record.ParsedNdefRecord;
23
24import android.app.Activity;
Jeff Hamilton79495342010-10-18 13:13:10 -050025import android.content.Intent;
Jeff Hamilton0215c982010-10-18 17:27:21 -050026import android.database.Cursor;
27import android.net.Uri;
28import android.nfc.FormatException;
Jeff Hamilton79495342010-10-18 13:13:10 -050029import android.nfc.NdefMessage;
30import android.nfc.NdefTag;
31import android.nfc.NfcAdapter;
Jeff Hamilton0215c982010-10-18 17:27:21 -050032import android.os.AsyncTask;
Jeff Hamilton79495342010-10-18 13:13:10 -050033import android.os.Bundle;
34import android.os.Handler;
Jeff Hamilton79495342010-10-18 13:13:10 -050035import android.os.Message;
Jeff Hamilton79495342010-10-18 13:13:10 -050036import android.util.Log;
Jeff Hamilton79495342010-10-18 13:13:10 -050037import android.view.LayoutInflater;
38import android.view.View;
39import android.view.View.OnClickListener;
40import android.view.WindowManager;
41import android.widget.Button;
42import android.widget.CheckBox;
43import android.widget.ImageView;
44import android.widget.LinearLayout;
45import android.widget.TextView;
46
Jeff Hamilton79495342010-10-18 13:13:10 -050047/**
48 * An {@link Activity} which handles a broadcast of a new tag that the device just discovered.
49 */
50public class TagViewer extends Activity implements OnClickListener, Handler.Callback {
51 static final String TAG = "SaveTag";
52 static final String EXTRA_TAG_DB_ID = "db_id";
53 static final String EXTRA_MESSAGE = "msg";
54
55 /** This activity will finish itself in this amount of time if the user doesn't do anything. */
Jeff Hamilton0215c982010-10-18 17:27:21 -050056 static final int ACTIVITY_TIMEOUT_MS = 5 * 1000;
Jeff Hamilton79495342010-10-18 13:13:10 -050057
Jeff Hamilton0215c982010-10-18 17:27:21 -050058 Uri mTagUri;
Jeff Hamilton79495342010-10-18 13:13:10 -050059 ImageView mIcon;
60 TextView mTitle;
61 CheckBox mStar;
62 Button mDeleteButton;
Jeff Hamilton0215c982010-10-18 17:27:21 -050063 Button mDoneButton;
Jeff Hamilton79495342010-10-18 13:13:10 -050064 NdefMessage[] mMessagesToSave = null;
Jeff Hamilton0215c982010-10-18 17:27:21 -050065 LinearLayout mTagContent;
Jeff Hamilton79495342010-10-18 13:13:10 -050066
67 @Override
68 protected void onCreate(Bundle savedInstanceState) {
69 super.onCreate(savedInstanceState);
70
71 getWindow().addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED
72 | WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD
73 | WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON
74 | WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON
75 | WindowManager.LayoutParams.FLAG_ALLOW_LOCK_WHILE_SCREEN_ON
76 | WindowManager.LayoutParams.FLAG_DIM_BEHIND
77 );
78
79 setContentView(R.layout.tag_viewer);
80
Jeff Hamilton0215c982010-10-18 17:27:21 -050081 mTagContent = (LinearLayout) findViewById(R.id.list);
Jeff Hamilton79495342010-10-18 13:13:10 -050082 mTitle = (TextView) findViewById(R.id.title);
83 mIcon = (ImageView) findViewById(R.id.icon);
84 mStar = (CheckBox) findViewById(R.id.star);
Jeff Hamilton0215c982010-10-18 17:27:21 -050085 mDeleteButton = (Button) findViewById(R.id.button_delete);
86 mDoneButton = (Button) findViewById(R.id.button_done);
Jeff Hamilton79495342010-10-18 13:13:10 -050087
88 mDeleteButton.setOnClickListener(this);
Jeff Hamilton0215c982010-10-18 17:27:21 -050089 mDoneButton.setOnClickListener(this);
Jeff Hamilton79495342010-10-18 13:13:10 -050090 mIcon.setImageResource(R.drawable.ic_launcher_nfc);
91
Jeff Hamilton0215c982010-10-18 17:27:21 -050092 resolveIntent(getIntent());
93 }
94
95 void resolveIntent(Intent intent) {
96 // Parse the intent
97 String action = intent.getAction();
98 if (NfcAdapter.ACTION_NDEF_TAG_DISCOVERED.equals(action)) {
99 // Get the messages from the tag
100 //TODO check if the tag is writable and offer to write it?
101 NdefTag tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
102 NdefMessage[] msgs = tag.getNdefMessages();
103 if (msgs == null || msgs.length == 0) {
104 Log.e(TAG, "No NDEF messages");
105 finish();
106 return;
Jeff Hamilton79495342010-10-18 13:13:10 -0500107 }
108
Jeff Hamilton0215c982010-10-18 17:27:21 -0500109 // Setup the views
110 setTitle(R.string.title_scanned_tag);
111 mStar.setVisibility(View.GONE);
Jeff Hamilton79495342010-10-18 13:13:10 -0500112
113 // Set a timer on this activity since it wasn't created by the user
Jeff Hamilton0215c982010-10-18 17:27:21 -0500114// new Handler(this).sendEmptyMessageDelayed(0, ACTIVITY_TIMEOUT_MS);
Jeff Hamilton79495342010-10-18 13:13:10 -0500115
Jeff Hamilton0215c982010-10-18 17:27:21 -0500116 // Mark messages that were just scanned for saving
117 mMessagesToSave = msgs;
118
119 // Build the views for the tag
120 buildTagViews(msgs);
121 } else if (Intent.ACTION_VIEW.equals(action)) {
122 // Setup the views
123 setTitle(R.string.title_existing_tag);
124 mStar.setVisibility(View.VISIBLE);
125
126 // Read the tag from the database asynchronously
127 mTagUri = intent.getData();
128 new LoadTagTask().execute(mTagUri);
129 } else {
130 Log.e(TAG, "Unknown intent " + intent);
Jeff Hamilton79495342010-10-18 13:13:10 -0500131 finish();
132 return;
133 }
Jeff Hamilton79495342010-10-18 13:13:10 -0500134 }
135
Jeff Hamilton0215c982010-10-18 17:27:21 -0500136 void buildTagViews(NdefMessage[] msgs) {
Jeff Hamilton79495342010-10-18 13:13:10 -0500137 if (msgs == null || msgs.length == 0) {
138 return;
139 }
140
Jeff Hamilton0215c982010-10-18 17:27:21 -0500141 LayoutInflater inflater = LayoutInflater.from(this);
142 LinearLayout content = mTagContent;
Jeff Hamilton79495342010-10-18 13:13:10 -0500143
Jeff Hamilton0215c982010-10-18 17:27:21 -0500144 // Clear out any old views in the content area, for example if you scan two tags in a row.
145 content.removeAllViews();
146
147 // Parse the first message in the list
148 //TODO figure out what to do when/if we support multiple messages per tag
149 ParsedNdefMessage parsedMsg = NdefMessageParser.parse(msgs[0]);
Jeff Hamilton79495342010-10-18 13:13:10 -0500150
151 // Build views for all of the sub records
152 for (ParsedNdefRecord record : parsedMsg.getRecords()) {
Jeff Hamilton0215c982010-10-18 17:27:21 -0500153 content.addView(record.getView(this, inflater, content));
154 inflater.inflate(R.layout.tag_divider, content, true);
Jeff Hamilton79495342010-10-18 13:13:10 -0500155 }
156 }
157
158 @Override
Jeff Hamilton0215c982010-10-18 17:27:21 -0500159 public void onNewIntent(Intent intent) {
160 // If we get a new scan while looking at a tag just save off the old tag...
161 if (mMessagesToSave != null) {
162 saveMessages(mMessagesToSave);
163 mMessagesToSave = null;
164 }
165
166 // ... and show the new one.
167 resolveIntent(intent);
168 }
169
170 @Override
Jeff Hamilton79495342010-10-18 13:13:10 -0500171 public void setTitle(CharSequence title) {
172 mTitle.setText(title);
173 }
174
175 @Override
176 public void onClick(View view) {
177 if (view == mDeleteButton) {
Jeff Hamilton0215c982010-10-18 17:27:21 -0500178 if (mTagUri == null) {
179 // The tag hasn't been saved yet, so indicate it shouldn't be saved
180 mMessagesToSave = null;
181 finish();
182 } else {
183 // The tag came from the database, start a service to delete it
184 Intent delete = new Intent(this, TagService.class);
185 delete.putExtra(TagService.EXTRA_DELETE_URI, mTagUri);
186 startService(delete);
187 finish();
188 }
189 } else if (view == mDoneButton) {
Jeff Hamilton79495342010-10-18 13:13:10 -0500190 finish();
191 }
192 }
193
194 @Override
195 public void onStop() {
196 super.onStop();
197 if (mMessagesToSave != null) {
198 saveMessages(mMessagesToSave);
199 }
200 }
201
Jeff Hamilton0215c982010-10-18 17:27:21 -0500202 /**
203 * Starts a service to asynchronously save the messages to the content provider.
204 */
Jeff Hamilton79495342010-10-18 13:13:10 -0500205 void saveMessages(NdefMessage[] msgs) {
206 Intent save = new Intent(this, TagService.class);
207 save.putExtra(TagService.EXTRA_SAVE_MSGS, msgs);
208 startService(save);
209 }
210
211 @Override
212 public boolean handleMessage(Message msg) {
213 finish();
214 return true;
215 }
Jeff Hamilton0215c982010-10-18 17:27:21 -0500216
217 /**
218 * Loads a tag from the database, parses it, and builds the views
219 */
220 final class LoadTagTask extends AsyncTask<Uri, Void, NdefMessage> {
221 @Override
222 public NdefMessage doInBackground(Uri... args) {
223 Cursor cursor = getContentResolver().query(args[0], new String[] { NdefMessages.BYTES },
224 null, null, null);
225 try {
226 if (cursor.moveToFirst()) {
227 return new NdefMessage(cursor.getBlob(0));
228 }
229 } catch (FormatException e) {
230 Log.e(TAG, "invalid tag format", e);
231 } finally {
232 if (cursor != null) cursor.close();
233 }
234 return null;
235 }
236
237 @Override
238 public void onPostExecute(NdefMessage msg) {
239 buildTagViews(new NdefMessage[] { msg });
240 }
241 }
Jeff Hamilton79495342010-10-18 13:13:10 -0500242}