diff options
author | Jason Parks <jparks@google.com> | 2010-11-02 19:51:21 -0700 |
---|---|---|
committer | Android (Google) Code Review <android-gerrit@google.com> | 2010-11-02 19:51:21 -0700 |
commit | a69d82371c36b62fefe5f837fa78e58dd5b21e63 (patch) | |
tree | 6248c9f390c849d3b5be7de540fc4010e8bb349e /src | |
parent | 0c4c3a3e9db3cea445937fbe739df2334a143240 (diff) | |
parent | 4a69635f60b448a143ae98392d9648d345046b52 (diff) | |
download | android_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.java | 174 | ||||
-rw-r--r-- | src/com/android/apps/tag/MyTagList.java | 443 | ||||
-rw-r--r-- | src/com/android/apps/tag/TagBrowserActivity.java | 2 | ||||
-rw-r--r-- | src/com/android/apps/tag/TagList.java | 7 | ||||
-rw-r--r-- | src/com/android/apps/tag/TagService.java | 56 | ||||
-rw-r--r-- | src/com/android/apps/tag/provider/TagContract.java | 6 | ||||
-rw-r--r-- | src/com/android/apps/tag/provider/TagDBHelper.java | 5 |
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 ");"); } |