summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorJason Parks <jparks@google.com>2010-11-02 19:51:21 -0700
committerAndroid (Google) Code Review <android-gerrit@google.com>2010-11-02 19:51:21 -0700
commita69d82371c36b62fefe5f837fa78e58dd5b21e63 (patch)
tree6248c9f390c849d3b5be7de540fc4010e8bb349e /src
parent0c4c3a3e9db3cea445937fbe739df2334a143240 (diff)
parent4a69635f60b448a143ae98392d9648d345046b52 (diff)
downloadandroid_packages_apps_Tag-a69d82371c36b62fefe5f837fa78e58dd5b21e63.tar.gz
android_packages_apps_Tag-a69d82371c36b62fefe5f837fa78e58dd5b21e63.tar.bz2
android_packages_apps_Tag-a69d82371c36b62fefe5f837fa78e58dd5b21e63.zip
Merge "My tag list restructuring." into gingerbread
Diffstat (limited to 'src')
-rw-r--r--src/com/android/apps/tag/EditTagActivity.java174
-rw-r--r--src/com/android/apps/tag/MyTagList.java443
-rw-r--r--src/com/android/apps/tag/TagBrowserActivity.java2
-rw-r--r--src/com/android/apps/tag/TagList.java7
-rw-r--r--src/com/android/apps/tag/TagService.java56
-rw-r--r--src/com/android/apps/tag/provider/TagContract.java6
-rw-r--r--src/com/android/apps/tag/provider/TagDBHelper.java5
7 files changed, 604 insertions, 89 deletions
diff --git a/src/com/android/apps/tag/EditTagActivity.java b/src/com/android/apps/tag/EditTagActivity.java
index b6d9cde..fc7690a 100644
--- a/src/com/android/apps/tag/EditTagActivity.java
+++ b/src/com/android/apps/tag/EditTagActivity.java
@@ -18,13 +18,14 @@ package com.android.apps.tag;
import com.android.apps.tag.message.NdefMessageParser;
import com.android.apps.tag.message.ParsedNdefMessage;
+import com.android.apps.tag.provider.TagContract.NdefMessages;
import com.android.apps.tag.record.ImageRecord;
import com.android.apps.tag.record.ParsedNdefRecord;
import com.android.apps.tag.record.RecordEditInfo;
+import com.android.apps.tag.record.RecordEditInfo.EditCallbacks;
import com.android.apps.tag.record.TextRecord;
import com.android.apps.tag.record.UriRecord;
import com.android.apps.tag.record.VCardRecord;
-import com.android.apps.tag.record.RecordEditInfo.EditCallbacks;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Lists;
@@ -32,18 +33,21 @@ import com.google.common.collect.Lists;
import android.app.Activity;
import android.app.Dialog;
import android.content.Intent;
+import android.database.Cursor;
import android.net.Uri;
+import android.nfc.FormatException;
import android.nfc.NdefMessage;
import android.nfc.NdefRecord;
import android.nfc.NfcAdapter;
+import android.os.AsyncTask;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
-import android.view.ViewGroup;
import android.view.View.OnClickListener;
+import android.view.ViewGroup;
import android.widget.CheckBox;
import android.widget.EditText;
@@ -63,9 +67,11 @@ import java.util.Set;
*/
public class EditTagActivity extends Activity implements OnClickListener, EditCallbacks {
+ private static final String LOG_TAG = "Tags";
+
private static final String BUNDLE_KEY_OUTSTANDING_PICK = "outstanding-pick";
protected static final int DIALOG_ID_ADD_CONTENT = 0;
- private static final String LOG_TAG = "Tags";
+ public static final String EXTRA_RESULT_MSG = "msg";
private static final Set<String> SUPPORTED_RECORD_TYPES = ImmutableSet.of(
ImageRecord.RECORD_TYPE,
@@ -95,7 +101,6 @@ public class EditTagActivity extends Activity implements OnClickListener, EditCa
private boolean mParsedIntent = false;
private EditText mTextView;
- private CheckBox mEnabled;
private LayoutInflater mInflater;
@@ -109,14 +114,14 @@ public class EditTagActivity extends Activity implements OnClickListener, EditCa
}
mInflater = LayoutInflater.from(this);
- findViewById(R.id.toggle_enabled_target).setOnClickListener(this);
findViewById(R.id.add_content_target).setOnClickListener(this);
+ findViewById(R.id.save).setOnClickListener(this);
+ findViewById(R.id.cancel).setOnClickListener(this);
mTextView = (EditText) findViewById(R.id.input_tag_text);
- mEnabled = (CheckBox) findViewById(R.id.toggle_enabled_checkbox);
mContentRoot = (ViewGroup) findViewById(R.id.content_parent);
- populateEditor();
+ resolveIntent();
}
/**
@@ -276,46 +281,95 @@ public class EditTagActivity extends Activity implements OnClickListener, EditCa
}
}
- private void populateEditor() {
- NdefMessage localMessage = NfcAdapter.getDefaultAdapter().getLocalNdefMessage();
+ interface GetTagQuery {
+ final static String[] PROJECTION = new String[] {
+ NdefMessages.BYTES
+ };
- if (Intent.ACTION_SEND.equals(getIntent().getAction()) && !mParsedIntent) {
- if (localMessage != null) {
- // TODO: prompt user for confirmation about wiping their old tag.
+ static final int COLUMN_BYTES = 0;
+ }
+
+ /**
+ * Loads a tag from the database, parses it, and builds the views.
+ */
+ final class LoadTagTask extends AsyncTask<Uri, Void, Cursor> {
+ @Override
+ public Cursor doInBackground(Uri... args) {
+ Cursor cursor = getContentResolver().query(args[0], GetTagQuery.PROJECTION,
+ null, null, null);
+
+ // Ensure the cursor loads its window.
+ if (cursor != null) {
+ cursor.getCount();
}
+ return cursor;
+ }
- if (buildFromIntent(getIntent())) {
+ @Override
+ public void onPostExecute(Cursor cursor) {
+ NdefMessage msg = null;
+ try {
+ if (cursor != null && cursor.moveToFirst()) {
+ msg = new NdefMessage(cursor.getBlob(GetTagQuery.COLUMN_BYTES));
+ if (msg != null) {
+ populateFromMessage(msg);
+ } else {
+ // TODO: do something more graceful.
+ finish();
+ }
+ }
+ } catch (FormatException e) {
+ Log.e(LOG_TAG, "Unable to parse tag for editing.", e);
+ } finally {
+ if (cursor != null) {
+ cursor.close();
+ }
+ }
+ }
+ }
+
+ private void resolveIntent() {
+ Intent intent = getIntent();
+
+ if (Intent.ACTION_SEND.equals(intent.getAction()) && !mParsedIntent) {
+ if (buildFromSendIntent(intent)) {
return;
}
mParsedIntent = true;
-
- } else if (localMessage == null) {
- mEnabled.setChecked(false);
return;
- } else {
- // Locally stored message.
- ParsedNdefMessage parsed = NdefMessageParser.parse(localMessage);
- List<ParsedNdefRecord> records = parsed.getRecords();
+ }
- // There is always a "Text" record for a My Tag.
- if (records.size() < 1) {
- Log.w(LOG_TAG, "Local record not in expected format");
- return;
- }
- mEnabled.setChecked(true);
- mTextView.setText(((TextRecord) records.get(0)).getText());
+ Uri uri = intent.getData();
+ if (uri != null) {
+ // Edit existing tag.
+ new LoadTagTask().execute(uri);
+ }
+ // else, new tag - do nothing.
+ }
- mRecords.clear();
- for (int i = 1, len = records.size(); i < len; i++) {
- RecordEditInfo editInfo = records.get(i).getEditInfo(this);
- if (editInfo != null) {
- addRecord(editInfo);
- }
+ private void populateFromMessage(NdefMessage refMessage) {
+ // Locally stored message.
+ ParsedNdefMessage parsed = NdefMessageParser.parse(refMessage);
+ List<ParsedNdefRecord> records = parsed.getRecords();
+
+ // TODO: loosen this restriction. Just check the type of the first record.
+ // There is always a "Text" record for a My Tag.
+ if (records.size() < 1) {
+ Log.w(LOG_TAG, "Message not in expected format");
+ return;
+ }
+ mTextView.setText(((TextRecord) records.get(0)).getText());
+
+ mRecords.clear();
+ for (int i = 1, len = records.size(); i < len; i++) {
+ RecordEditInfo editInfo = records.get(i).getEditInfo(this);
+ if (editInfo != null) {
+ addRecord(editInfo);
}
- rebuildChildViews();
}
+ rebuildChildViews();
}
/**
@@ -323,7 +377,7 @@ public class EditTagActivity extends Activity implements OnClickListener, EditCa
* @param intent the {@link Intent} to parse.
* @return whether or not the {@link Intent} could be handled.
*/
- private boolean buildFromIntent(final Intent intent) {
+ private boolean buildFromSendIntent(final Intent intent) {
String type = intent.getType();
if ("text/plain".equals(type)) {
@@ -338,15 +392,13 @@ public class EditTagActivity extends Activity implements OnClickListener, EditCa
mTextView.setText("");
mRecords.add(new UriRecord.UriRecordEditInfo(text));
rebuildChildViews();
+ return true;
} catch (MalformedURLException ex) {
// Ignore. Just treat as plain text.
mTextView.setText((text == null) ? "" : text);
}
- mEnabled.setChecked(true);
- onSave();
- return true;
} else if ("text/x-vcard".equals(type)) {
Uri stream = (Uri) getIntent().getParcelableExtra(Intent.EXTRA_STREAM);
if (stream != null) {
@@ -354,28 +406,21 @@ public class EditTagActivity extends Activity implements OnClickListener, EditCa
if (editInfo != null) {
mRecords.add(editInfo);
rebuildChildViews();
- onSave();
return true;
}
}
}
- // TODO: handle vcards and images.
+ // TODO: handle images.
+
return false;
}
/**
- * Persists content to store.
+ * Saves the content of the tag.
*/
- private void onSave() {
+ private void saveAndFinish() {
String text = mTextView.getText().toString();
- NfcAdapter nfc = NfcAdapter.getDefaultAdapter();
-
- if (!mEnabled.isChecked()) {
- nfc.setLocalNdefMessage(null);
- return;
- }
-
Locale locale = getResources().getConfiguration().locale;
ArrayList<NdefRecord> values = Lists.newArrayList(
TextRecord.newTextRecord(text, locale)
@@ -383,34 +428,25 @@ public class EditTagActivity extends Activity implements OnClickListener, EditCa
values.addAll(getValues());
- Log.d(LOG_TAG, "Writing local NdefMessage from tag app....");
- nfc.setLocalNdefMessage(new NdefMessage(values.toArray(new NdefRecord[values.size()])));
- }
-
- @Override
- public void onPause() {
- super.onPause();
- onSave();
+ NdefMessage msg = new NdefMessage(values.toArray(new NdefRecord[values.size()]));
+ Intent result = new Intent();
+ result.putExtra(EXTRA_RESULT_MSG, msg);
+ setResult(RESULT_OK, result);
+ finish();
}
@Override
public void onClick(View target) {
switch (target.getId()) {
- case R.id.toggle_enabled_target:
- boolean enabled = !mEnabled.isChecked();
- mEnabled.setChecked(enabled);
-
- // TODO: Persist to some store.
- if (enabled) {
- onSave();
- } else {
- NfcAdapter.getDefaultAdapter().setLocalNdefMessage(null);
- }
- break;
-
case R.id.add_content_target:
showAddContentDialog();
break;
+ case R.id.save:
+ saveAndFinish();
+ break;
+ case R.id.cancel:
+ finish();
+ break;
}
}
diff --git a/src/com/android/apps/tag/MyTagList.java b/src/com/android/apps/tag/MyTagList.java
new file mode 100644
index 0000000..bf0feac
--- /dev/null
+++ b/src/com/android/apps/tag/MyTagList.java
@@ -0,0 +1,443 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.apps.tag;
+
+import com.android.apps.tag.provider.TagContract.NdefMessages;
+import com.google.common.base.Preconditions;
+import com.google.common.collect.Lists;
+
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.content.ContentUris;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.database.CharArrayBuffer;
+import android.database.Cursor;
+import android.nfc.FormatException;
+import android.nfc.NdefMessage;
+import android.nfc.NfcAdapter;
+import android.os.AsyncTask;
+import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.AdapterView;
+import android.widget.AdapterView.OnItemClickListener;
+import android.widget.CheckBox;
+import android.widget.CursorAdapter;
+import android.widget.ListView;
+import android.widget.SimpleAdapter;
+import android.widget.TextView;
+import android.widget.Toast;
+
+import java.lang.ref.WeakReference;
+import java.util.ArrayList;
+import java.util.HashMap;
+
+/**
+ * Displays the list of tags that can be set as "My tag", and allows the user to select the
+ * active tag that the device shares.
+ */
+public class MyTagList extends Activity implements OnItemClickListener, View.OnClickListener {
+
+ static final String TAG = "TagList";
+
+ private static final int REQUEST_EDIT = 0;
+ private static final int DIALOG_ID_SELECT_ACTIVE_TAG = 0;
+
+ private static final String BUNDLE_KEY_TAG_ID_IN_EDIT = "tag-edit";
+ private static final String PREF_KEY_ACTIVE_TAG = "active-my-tag";
+
+ private View mSelectActiveTagAnchor;
+ private View mActiveTagDetails;
+ private CheckBox mEnabled;
+ private ListView mList;
+
+ private TagAdapter mAdapter;
+ private long mActiveTagId;
+ private NdefMessage mActiveTag;
+ private boolean mInitialLoadComplete = false;
+
+ private WeakReference<SelectActiveTagDialog> mSelectActiveTagDialog;
+ private long mTagIdInEdit = -1;
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ setContentView(R.layout.my_tag_activity);
+
+ if (savedInstanceState != null) {
+ mTagIdInEdit = savedInstanceState.getLong(BUNDLE_KEY_TAG_ID_IN_EDIT, -1);
+ }
+
+ // Set up the check box to toggle My tag sharing.
+ mEnabled = (CheckBox) findViewById(R.id.toggle_enabled_checkbox);
+ mEnabled.setChecked(false); // Set after initial data load completes.
+ findViewById(R.id.toggle_enabled_target).setOnClickListener(this);
+
+ // Setup the active tag selector.
+ mActiveTagDetails = findViewById(R.id.active_tag_details);
+ mSelectActiveTagAnchor = findViewById(R.id.choose_my_tag);
+ findViewById(R.id.active_tag).setOnClickListener(this);
+ updateActiveTagView(null); // Filled in after initial data load.
+
+ mActiveTagId = getPreferences(Context.MODE_PRIVATE).getLong(PREF_KEY_ACTIVE_TAG, -1);
+
+ // Setup the list
+ mAdapter = new TagAdapter(this);
+ mList = (ListView) findViewById(android.R.id.list);
+ mList.setAdapter(mAdapter);
+ mList.setOnItemClickListener(this);
+ registerForContextMenu(mList);
+ findViewById(R.id.add_tag).setOnClickListener(this);
+
+ // Kick off an async task to load the tags.
+ new TagLoaderTask().execute((Void[]) null);
+ }
+
+ @Override
+ protected void onRestart() {
+ super.onRestart();
+ mTagIdInEdit = -1;
+ }
+
+ @Override
+ protected void onSaveInstanceState(Bundle outState) {
+ super.onSaveInstanceState(outState);
+ outState.putLong(BUNDLE_KEY_TAG_ID_IN_EDIT, mTagIdInEdit);
+ }
+
+ @Override
+ protected void onDestroy() {
+ if (mAdapter != null) {
+ mAdapter.changeCursor(null);
+ }
+ super.onDestroy();
+ }
+
+ @Override
+ public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
+ // TODO: use implicit Intent?
+ Intent intent = new Intent(this, EditTagActivity.class);
+ intent.setData(ContentUris.withAppendedId(NdefMessages.CONTENT_URI, id));
+ mTagIdInEdit = id;
+ startActivityForResult(intent, REQUEST_EDIT);
+ }
+
+ public void setEmptyView() {
+ // TODO: set empty view.
+ }
+
+ public interface TagQuery {
+ static final String[] PROJECTION = new String[] {
+ NdefMessages._ID, // 0
+ NdefMessages.DATE, // 1
+ NdefMessages.TITLE, // 2
+ NdefMessages.BYTES, // 3
+ };
+
+ static final int COLUMN_ID = 0;
+ static final int COLUMN_DATE = 1;
+ static final int COLUMN_TITLE = 2;
+ static final int COLUMN_BYTES = 3;
+ }
+
+ /**
+ * Asynchronously loads the tags info from the database.
+ */
+ final class TagLoaderTask extends AsyncTask<Void, Void, Cursor> {
+ @Override
+ public Cursor doInBackground(Void... args) {
+ // Don't setup the empty view until after the first load
+ // so the empty text doesn't flash when first loading the
+ // activity.
+ mList.setEmptyView(null);
+ Cursor cursor = getContentResolver().query(
+ NdefMessages.CONTENT_URI,
+ TagQuery.PROJECTION,
+ NdefMessages.IS_MY_TAG + "=1",
+ null, NdefMessages.DATE + " DESC");
+
+ // Ensure the cursor executes and fills its window
+ if (cursor != null) cursor.getCount();
+ return cursor;
+ }
+
+ @Override
+ protected void onPostExecute(Cursor cursor) {
+ boolean firstLoad = !mInitialLoadComplete;
+ if (!mInitialLoadComplete) {
+ mInitialLoadComplete = true;
+ }
+
+ if (cursor == null || cursor.getCount() == 0) {
+ setEmptyView();
+ } else if (mActiveTagId != -1) {
+ mAdapter.changeCursor(cursor);
+
+ // Find the active tag.
+ cursor.moveToPosition(-1);
+ while (cursor.moveToNext()) {
+ if (mActiveTagId == cursor.getLong(TagQuery.COLUMN_ID)) {
+ selectActiveTag(cursor.getPosition());
+
+ // If there was an existing shared tag, we update the contents, since
+ // the active tag contents may have been changed. This also forces the
+ // active tag to be in sync with what the NfcAdapter.
+ if (NfcAdapter.getDefaultAdapter().getLocalNdefMessage() != null) {
+ enableSharing();
+ }
+ break;
+ }
+ }
+ }
+
+
+ SelectActiveTagDialog dialog = (mSelectActiveTagDialog == null)
+ ? null : mSelectActiveTagDialog.get();
+ if (dialog != null) {
+ dialog.setData(cursor);
+ }
+ }
+ }
+
+ /**
+ * Struct to hold pointers to views in the list items to save time at view binding time.
+ */
+ static final class ViewHolder {
+ public CharArrayBuffer titleBuffer;
+ public TextView mainLine;
+ }
+
+ /**
+ * Adapter to display the the My tag entries.
+ */
+ public class TagAdapter extends CursorAdapter {
+ private final LayoutInflater mInflater;
+
+ public TagAdapter(Context context) {
+ super(context, null, false);
+ mInflater = LayoutInflater.from(context);
+ }
+
+ @Override
+ public void bindView(View view, Context context, Cursor cursor) {
+ ViewHolder holder = (ViewHolder) view.getTag();
+
+ CharArrayBuffer buf = holder.titleBuffer;
+ cursor.copyStringToBuffer(TagQuery.COLUMN_TITLE, buf);
+ holder.mainLine.setText(buf.data, 0, buf.sizeCopied);
+ }
+
+ @Override
+ public View newView(Context context, Cursor cursor, ViewGroup parent) {
+ View view = mInflater.inflate(R.layout.tag_list_item, null);
+
+ // Cache items for the view
+ ViewHolder holder = new ViewHolder();
+ holder.titleBuffer = new CharArrayBuffer(64);
+ holder.mainLine = (TextView) view.findViewById(R.id.title);
+ view.findViewById(R.id.date).setVisibility(View.GONE);
+ view.setTag(holder);
+
+ return view;
+ }
+
+ @Override
+ public void onContentChanged() {
+ // Kick off an async query to refresh the list
+ new TagLoaderTask().execute((Void[]) null);
+ }
+ }
+
+ @Override
+ public void onClick(View target) {
+ switch (target.getId()) {
+ case R.id.toggle_enabled_target:
+ boolean enabled = !mEnabled.isChecked();
+ if (enabled) {
+ if (mActiveTag != null) {
+ enableSharing();
+ return;
+ }
+ // TODO: just disable the checkbox when no tag is set
+ Toast.makeText(
+ this,
+ "You must select a tag to share first.",
+ Toast.LENGTH_SHORT).show();
+ }
+
+ disableSharing();
+ break;
+
+ case R.id.add_tag:
+ // TODO: use implicit intents.
+ Intent intent = new Intent(this, EditTagActivity.class);
+ startActivityForResult(intent, REQUEST_EDIT);
+ break;
+
+ case R.id.active_tag:
+ showDialog(DIALOG_ID_SELECT_ACTIVE_TAG);
+ break;
+ }
+ }
+
+ @Override
+ protected void onActivityResult(int requestCode, int resultCode, Intent data) {
+ if (requestCode == REQUEST_EDIT && resultCode == RESULT_OK) {
+ NdefMessage msg = (NdefMessage) Preconditions.checkNotNull(
+ data.getParcelableExtra(EditTagActivity.EXTRA_RESULT_MSG));
+
+ if (mTagIdInEdit != -1) {
+ TagService.updateMyMessage(this, mTagIdInEdit, msg);
+ } else {
+ TagService.saveMyMessages(this, new NdefMessage[] { msg });
+ }
+ }
+ }
+
+ @Override
+ protected Dialog onCreateDialog(int id, Bundle args) {
+ if (id == DIALOG_ID_SELECT_ACTIVE_TAG) {
+ mSelectActiveTagDialog = new WeakReference<SelectActiveTagDialog>(
+ new SelectActiveTagDialog(this, mAdapter.getCursor()));
+ return mSelectActiveTagDialog.get();
+ }
+ return super.onCreateDialog(id, args);
+ }
+
+ /**
+ * Selects the tag to be used as the "My tag" shared tag.
+ *
+ * This does not necessarily persist the selection to the {@code NfcAdapter}. That must be done
+ * via {@link #enableSharing}. However, it will call {@link #disableSharing} if the tag
+ * is invalid.
+ */
+ private void selectActiveTag(int position) {
+ Cursor cursor = mAdapter.getCursor();
+ if (cursor != null && cursor.moveToPosition(position)) {
+ mActiveTagId = cursor.getLong(TagQuery.COLUMN_ID);
+
+ try {
+ mActiveTag = new NdefMessage(cursor.getBlob(TagQuery.COLUMN_BYTES));
+
+ // Persist active tag info to preferences.
+ getPreferences(Context.MODE_PRIVATE)
+ .edit()
+ .putLong(PREF_KEY_ACTIVE_TAG, mActiveTagId)
+ .apply();
+
+ // Notify NFC adapter of the My tag contents.
+ updateActiveTagView(cursor.getString(TagQuery.COLUMN_TITLE));
+
+ } catch (FormatException e) {
+ // TODO: handle.
+ disableSharing();
+ }
+ } else {
+ updateActiveTagView(null);
+ disableSharing();
+ }
+ }
+
+ private void enableSharing() {
+ mEnabled.setChecked(true);
+ NfcAdapter.getDefaultAdapter().setLocalNdefMessage(Preconditions.checkNotNull(mActiveTag));
+ }
+
+ private void disableSharing() {
+ mEnabled.setChecked(false);
+ NfcAdapter.getDefaultAdapter().setLocalNdefMessage(null);
+ }
+
+ private void updateActiveTagView(String title) {
+ if (title == null) {
+ mActiveTagDetails.setVisibility(View.GONE);
+ mSelectActiveTagAnchor.setVisibility(View.VISIBLE);
+ } else {
+ mActiveTagDetails.setVisibility(View.VISIBLE);
+ ((TextView) mActiveTagDetails.findViewById(R.id.active_tag_title)).setText(title);
+ mSelectActiveTagAnchor.setVisibility(View.GONE);
+ }
+ }
+
+ class SelectActiveTagDialog extends AlertDialog
+ implements DialogInterface.OnClickListener, OnItemClickListener {
+
+ private final ArrayList<HashMap<String, String>> mData;
+ private final SimpleAdapter mSelectAdapter;
+
+ protected SelectActiveTagDialog(Context context, Cursor cursor) {
+ super(context);
+
+ setTitle(context.getResources().getString(R.string.choose_my_tag));
+ LayoutInflater inflater = LayoutInflater.from(context);
+ ListView list = new ListView(MyTagList.this);
+
+ mData = Lists.newArrayList();
+ mSelectAdapter = new SimpleAdapter(
+ context,
+ mData,
+ android.R.layout.simple_list_item_1,
+ new String[] { "title" },
+ new int[] { android.R.id.text1 });
+
+ list.setAdapter(mSelectAdapter);
+ list.setOnItemClickListener(this);
+ setView(list);
+ setIcon(0);
+ setButton(
+ DialogInterface.BUTTON_POSITIVE,
+ context.getString(android.R.string.cancel),
+ this);
+
+ setData(cursor);
+ }
+
+ public void setData(final Cursor cursor) {
+ if ((cursor == null) || (cursor.getCount() == 0)) {
+ cancel();
+ return;
+ }
+ mData.clear();
+
+ cursor.moveToPosition(-1);
+ while (cursor.moveToNext()) {
+ mData.add(new HashMap<String, String>() {{
+ put("title", cursor.getString(MyTagList.TagQuery.COLUMN_TITLE));
+ }});
+ }
+
+ mSelectAdapter.notifyDataSetChanged();
+ }
+
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ cancel();
+ }
+
+ @Override
+ public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
+ selectActiveTag(position);
+ enableSharing();
+ cancel();
+ }
+ }
+}
diff --git a/src/com/android/apps/tag/TagBrowserActivity.java b/src/com/android/apps/tag/TagBrowserActivity.java
index f0e8bda..ef7f364 100644
--- a/src/com/android/apps/tag/TagBrowserActivity.java
+++ b/src/com/android/apps/tag/TagBrowserActivity.java
@@ -63,7 +63,7 @@ public class TagBrowserActivity extends TabActivity implements DialogInterface.O
tabHost.addTab(tabHost.newTabSpec("mytag")
.setIndicator(getText(R.string.tab_my_tag),
res.getDrawable(R.drawable.ic_tab_my_tag))
- .setContent(new Intent().setClass(this, EditTagActivity.class)));
+ .setContent(new Intent().setClass(this, MyTagList.class)));
SharedPreferences preferences = getPreferences(Context.MODE_PRIVATE);
if (!preferences.getBoolean(PREF_KEY_SHOW_INTRO, false)) {
diff --git a/src/com/android/apps/tag/TagList.java b/src/com/android/apps/tag/TagList.java
index ccb20ba..f3d9c82 100644
--- a/src/com/android/apps/tag/TagList.java
+++ b/src/com/android/apps/tag/TagList.java
@@ -17,6 +17,7 @@
package com.android.apps.tag;
import com.android.apps.tag.provider.TagContract.NdefMessages;
+import com.android.apps.tag.provider.TagProvider;
import android.app.Activity;
import android.app.ListActivity;
@@ -117,11 +118,13 @@ public class TagList extends ListActivity implements OnClickListener {
final class TagLoaderTask extends AsyncTask<Void, Void, Cursor> {
@Override
public Cursor doInBackground(Void... args) {
- String selection = mShowStarredOnly ? NdefMessages.STARRED + "=1" : null;
+ String starred = mShowStarredOnly ? NdefMessages.STARRED + "=1" : null;
+ String notMyTag = NdefMessages.IS_MY_TAG + "!=1";
+
Cursor cursor = getContentResolver().query(
NdefMessages.CONTENT_URI,
TagQuery.PROJECTION,
- selection,
+ TagProvider.concatenateWhere(starred, notMyTag),
null, NdefMessages.DATE + " DESC");
// Ensure the cursor executes and fills its window
diff --git a/src/com/android/apps/tag/TagService.java b/src/com/android/apps/tag/TagService.java
index dee2f00..5847bc2 100644
--- a/src/com/android/apps/tag/TagService.java
+++ b/src/com/android/apps/tag/TagService.java
@@ -38,6 +38,8 @@ public class TagService extends IntentService {
private static final String EXTRA_UNSTAR_URI = "remove_star";
private static final String EXTRA_STARRED = "starred";
private static final String EXTRA_PENDING_INTENT = "pending";
+ private static final String EXTRA_SAVE_IN_MY_TAGS = "my_tags";
+ private static final String EXTRA_REPLACE_ID = "replace";
private static final boolean DEBUG = true;
@@ -51,19 +53,32 @@ public class TagService extends IntentService {
Parcelable[] msgs = intent.getParcelableArrayExtra(EXTRA_SAVE_MSGS);
NdefMessage msg = (NdefMessage) msgs[0];
- ContentValues values = NdefMessages.toValues(this, msg, false, System.currentTimeMillis());
- Uri uri = getContentResolver().insert(NdefMessages.CONTENT_URI, values);
-
- if (intent.hasExtra(EXTRA_PENDING_INTENT)) {
- Intent result = new Intent();
- result.setData(uri);
-
- PendingIntent pending = (PendingIntent) intent.getParcelableExtra(EXTRA_PENDING_INTENT);
-
- try {
- pending.send(this, 0, result);
- } catch (CanceledException e) {
- if (DEBUG) Log.d(TAG, "Pending intent was canceled.");
+ ContentValues values = NdefMessages.toValues(
+ this, msg,
+ intent.getBooleanExtra(EXTRA_STARRED, false),
+ intent.getBooleanExtra(EXTRA_SAVE_IN_MY_TAGS, false),
+ System.currentTimeMillis());
+
+ if (intent.hasExtra(EXTRA_REPLACE_ID)) {
+ long id = intent.getLongExtra(EXTRA_REPLACE_ID, 0);
+ String where = NdefMessages._ID + "=" + id;
+ getContentResolver().update(NdefMessages.CONTENT_URI, values, where, null);
+ } else {
+ Uri uri = getContentResolver().insert(NdefMessages.CONTENT_URI, values);
+
+ if (intent.hasExtra(EXTRA_PENDING_INTENT)) {
+ Intent result = new Intent();
+ result.setData(uri);
+
+ PendingIntent pending = (PendingIntent) intent.getParcelableExtra(
+ EXTRA_PENDING_INTENT);
+ if (pending != null) {
+ try {
+ pending.send(this, 0, result);
+ } catch (CanceledException e) {
+ if (DEBUG) Log.d(TAG, "Pending intent was canceled.");
+ }
+ }
}
}
@@ -100,6 +115,21 @@ public class TagService extends IntentService {
context.startService(intent);
}
+ public static void saveMyMessages(Context context, NdefMessage[] msgs) {
+ Intent intent = new Intent(context, TagService.class);
+ intent.putExtra(TagService.EXTRA_SAVE_MSGS, msgs);
+ intent.putExtra(TagService.EXTRA_SAVE_IN_MY_TAGS, true);
+ context.startService(intent);
+ }
+
+ public static void updateMyMessage(Context context, long id, NdefMessage msg) {
+ Intent intent = new Intent(context, TagService.class);
+ intent.putExtra(TagService.EXTRA_SAVE_MSGS, new NdefMessage[] { msg });
+ intent.putExtra(TagService.EXTRA_SAVE_IN_MY_TAGS, true);
+ intent.putExtra(TagService.EXTRA_REPLACE_ID, id);
+ context.startService(intent);
+ }
+
public static void delete(Context context, Uri uri) {
Intent intent = new Intent(context, TagService.class);
intent.putExtra(TagService.EXTRA_DELETE_URI, uri);
diff --git a/src/com/android/apps/tag/provider/TagContract.java b/src/com/android/apps/tag/provider/TagContract.java
index acc487e..2d66c7f 100644
--- a/src/com/android/apps/tag/provider/TagContract.java
+++ b/src/com/android/apps/tag/provider/TagContract.java
@@ -61,7 +61,7 @@ public class TagContract {
public static final String BYTES = "bytes";
public static final String DATE = "date";
public static final String STARRED = "starred";
-
+ public static final String IS_MY_TAG = "mytag";
public static class MIME implements OpenableColumns {
public static final String CONTENT_DIRECTORY_MIME = "mime";
@@ -72,12 +72,14 @@ public class TagContract {
/**
* Converts an NdefMessage to ContentValues that can be insrted into this table.
*/
- public static ContentValues toValues(Context context, NdefMessage msg, boolean isStarred, long date) {
+ public static ContentValues toValues(Context context, NdefMessage msg, boolean isStarred,
+ boolean isMyTag, long date) {
ParsedNdefMessage parsedMsg = NdefMessageParser.parse(msg);
ContentValues values = new ContentValues();
values.put(BYTES, msg.toByteArray());
values.put(DATE, date);
values.put(STARRED, isStarred ? 1 : 0);
+ values.put(IS_MY_TAG, isMyTag ? 1 : 0);
values.put(TITLE, parsedMsg.getSnippet(context, Locale.getDefault()));
return values;
}
diff --git a/src/com/android/apps/tag/provider/TagDBHelper.java b/src/com/android/apps/tag/provider/TagDBHelper.java
index 26cd2cb..82df6c0 100644
--- a/src/com/android/apps/tag/provider/TagDBHelper.java
+++ b/src/com/android/apps/tag/provider/TagDBHelper.java
@@ -29,7 +29,7 @@ import android.database.sqlite.SQLiteOpenHelper;
public class TagDBHelper extends SQLiteOpenHelper {
private static final String DATABASE_NAME = "tags.db";
- private static final int DATABASE_VERSION = 12;
+ private static final int DATABASE_VERSION = 13;
public static final String TABLE_NAME_NDEF_MESSAGES = "ndef_msgs";
@@ -50,7 +50,8 @@ public class TagDBHelper extends SQLiteOpenHelper {
NdefMessages.DATE + " INTEGER NOT NULL, " +
NdefMessages.TITLE + " TEXT NOT NULL DEFAULT ''," +
NdefMessages.BYTES + " BLOB NOT NULL, " +
- NdefMessages.STARRED + " INTEGER NOT NULL DEFAULT 0" + // boolean
+ NdefMessages.STARRED + " INTEGER NOT NULL DEFAULT 0," + // boolean
+ NdefMessages.IS_MY_TAG + " INTEGER NOT NULL DEFAULT 0" + // boolean
");");
}