Remove the Tag app.

It's moving to package/apps/Tag.

Change-Id: I1f800fd718b3a06feeeba8fa1564acd3ca173510
This commit is contained in:
Jeff Hamilton
2010-10-18 13:14:21 -05:00
parent f8580cf676
commit 15b480d052
45 changed files with 0 additions and 2480 deletions

2
apps/Tag/.gitignore vendored
View File

@@ -1,2 +0,0 @@
*.swp

View File

@@ -1,20 +0,0 @@
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE_TAGS := optional
LOCAL_STATIC_JAVA_LIBRARIES := guava
# Only compile source java files in this apk.
LOCAL_SRC_FILES := $(call all-java-files-under, src)
LOCAL_PACKAGE_NAME := TagApp
# LOCAL_SDK_VERSION := current
LOCAL_PROGUARD_ENABLED := disabled
include $(BUILD_PACKAGE)
# Use the following include to make our test apk.
include $(call all-makefiles-under,$(LOCAL_PATH))

View File

@@ -1,54 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- 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.
-->
<!-- Declare the contents of this Android application. The namespace
attribute brings in the Android platform namespace, and the package
supplies a unique name for the application. When writing your
own application, the package name must be changed from "com.example.*"
to come from a domain that you own or have control over. -->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.apps.tag"
>
<uses-permission android:name="android.permission.CALL_PHONE" />
<uses-permission android:name="android.permission.NFC" />
<application android:label="Tags">
<activity android:name="TagBrowserActivity"
android:icon="@drawable/ic_launcher_nfc"
android:theme="@android:style/Theme.NoTitleBar"
>
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<activity android:name="TagList" />
<activity android:name="TagViewer"
android:theme="@android:style/Theme.NoTitleBar"
>
<intent-filter>
<action android:name="android.nfc.action.NDEF_TAG_DISCOVERED"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</activity>
<service android:name="TagService" />
</application>
</manifest>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 568 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 941 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 459 B

View File

@@ -1,21 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2008 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.
-->
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_selected="true" android:state_pressed="false" android:drawable="@drawable/ic_tab_selected_starred" />
<item android:drawable="@drawable/ic_tab_unselected_starred" />
</selector>

View File

@@ -1,38 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
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.
-->
<TabHost xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@android:id/tabhost"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TabWidget
android:id="@android:id/tabs"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<FrameLayout
android:id="@android:id/tabcontent"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
</TabHost>

View File

@@ -1,22 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
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.
-->
<View xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?android:attr/listDivider"
/>

View File

@@ -1,40 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
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.
-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:padding="4dip"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="@+id/title"
android:padding="4dip"
android:textAppearance="?android:attr/textAppearanceMedium"
android:layout_width="match_parent"
android:layout_height="wrap_content"
/>
<TextView
android:id="@+id/date"
android:padding="4dip"
android:textAppearance="?android:attr/textAppearanceSmall"
android:layout_width="match_parent"
android:layout_height="wrap_content"
/>
</LinearLayout>

View File

@@ -1,26 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
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.
-->
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/text"
android:padding="4dip"
android:textAppearance="?android:attr/textAppearanceMedium"
android:layout_width="match_parent"
android:layout_height="?android:attr/listPreferredItemHeight"
android:singleLine="true"
android:gravity="center_vertical"
/>

View File

@@ -1,55 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
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.
-->
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="?android:attr/listPreferredItemHeight"
android:paddingTop="4dip"
android:paddingBottom="4dip"
>
<ImageView android:id="@+id/icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_centerVertical="true"
android:paddingLeft="8dip"
android:paddingRight="8dip"
/>
<TextView android:id="@+id/primary"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_toRightOf="@id/icon"
android:layout_marginTop="4dip"
android:textAppearance="?android:attr/textAppearanceMedium"
/>
<TextView android:id="@+id/secondary"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/primary"
android:layout_alignLeft="@id/primary"
android:textAppearance="?android:attr/textAppearanceSmall"
/>
</RelativeLayout>

View File

@@ -1,118 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- 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.
-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
>
<!-- Title -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="56dip"
android:orientation="horizontal"
android:background="@android:color/black"
>
<ImageView android:id="@+id/icon"
android:layout_width="32dip"
android:layout_height="32dip"
android:layout_gravity="center_vertical"
/>
<TextView android:id="@+id/title"
android:layout_width="0dip"
android:layout_weight="1"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:singleLine="true"
android:textAppearance="?android:attr/textAppearanceMedium"
/>
<CheckBox android:id="@+id/star"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
style="?android:attr/starStyle"
/>
</LinearLayout>
<!-- Content -->
<ScrollView
android:layout_width="match_parent"
android:layout_height="0dip"
android:layout_weight="1"
android:background="@android:color/white"
>
<LinearLayout android:id="@+id/list"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
/>
</ScrollView>
<!-- Bottom button area -->
<TextView android:id="@+id/cancel_help_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingLeft="4dip"
android:paddingRight="4dip"
android:text="@string/cancel_help_text"
android:textAppearance="?android:attr/textAppearanceMedium"
android:background="@android:color/black"
android:gravity="center"
/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
style="@style/ButtonBar"
>
<Button android:id="@+id/btn_delete"
android:layout_width="0dip"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="@string/button_delete"
/>
<Button android:id="@+id/btn_cancel"
android:layout_width="0dip"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="@android:string/cancel"
/>
</LinearLayout>
</LinearLayout>

View File

@@ -1,42 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- 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.
-->
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<!-- The title of the tab that displays all recently scanned NFC tags -->
<string name="tab_tags">Tags</string>
<!-- The title of the tab that displays all starred NFC tags -->
<string name="tab_starred">Starred</string>
<!-- The title displayed for unknown tag types -->
<string name="tag_unknown">Unknown tag type</string>
<!-- The title displayed for an empty tag -->
<string name="tag_empty">Empty tag</string>
<!-- Button label indicating that the user wants to delete a tag -->
<string name="button_delete">Delete</string>
<!-- String describing that if the user doesn't want to save a tag they should touch the button labeled Cancel. The text for the cancel button comes from the system string android.R.string.cancel. -->
<string name="cancel_help_text">To skip adding this tag to your collection, press Cancel</string>
<!-- String displayed for an action to send a text message to a phone number -->
<string name="action_text">Text <xliff:g id="phone_number">%s</xliff:g></string>
<!-- String displayed for an action to call a phone number -->
<string name="action_call">Call <xliff:g id="phone_number">%s</xliff:g></string>
</resources>

View File

@@ -1,25 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- 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.
-->
<resources>
<style name="ButtonBar">
<item name="android:paddingTop">5dip</item>
<item name="android:paddingLeft">4dip</item>
<item name="android:paddingRight">4dip</item>
<item name="android:paddingBottom">1dip</item>
<item name="android:background">@android:color/black</item>
</style>
</resources>

View File

@@ -1,224 +0,0 @@
/*
* 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;
/**
* Tags that we've seen in the field, for testing purposes.
*/
public class MockNdefMessages {
/**
* A real NFC tag containing an NFC "smart poster". This smart poster
* consists of the text "NFC Forum Type 4 Tag" in english combined with
* the URL "http://www.nxp.com/nfc"
*/
public static final byte[] REAL_NFC_MSG = new byte[] {
(byte) 0xd1, // MB=1 ME=1 CF=0 SR=1 IL=0 TNF=001
(byte) 0x02, // Type Length = 2
(byte) 0x2b, // Payload Length = 43
(byte) 0x53, (byte) 0x70, // Type = {'S', 'p'} (smart poster)
// begin smart poster payload
// begin smart poster record #1
(byte) 0x91, // MB=1 ME=0 CF=0 SR=1 IL=0 TNF=001
(byte) 0x01, // Type Length = 1
(byte) 0x17, // Payload Length = 23
(byte) 0x54, // Type = {'T'} (Text data)
(byte) 0x02, // UTF-8 encoding, language code length = 2
(byte) 0x65, (byte) 0x6e, // language = {'e', 'n'} (english)
// Begin text data within smart poster record #1
(byte) 0x4e, // 'N'
(byte) 0x46, // 'F'
(byte) 0x43, // 'C'
(byte) 0x20, // ' '
(byte) 0x46, // 'F'
(byte) 0x6f, // 'o'
(byte) 0x72, // 'r'
(byte) 0x75, // 'u'
(byte) 0x6d, // 'm'
(byte) 0x20, // ' '
(byte) 0x54, // 'T'
(byte) 0x79, // 'y'
(byte) 0x70, // 'p'
(byte) 0x65, // 'e'
(byte) 0x20, // ' '
(byte) 0x34, // '4'
(byte) 0x20, // ' '
(byte) 0x54, // 'T'
(byte) 0x61, // 'a'
(byte) 0x67, // 'g'
// end Text data within smart poster record #1
// end smart poster record #1
// begin smart poster record #2
(byte) 0x51, // MB=0 ME=1 CF=0 SR=1 IL=0 TNF=001
(byte) 0x01, // Type Length = 1
(byte) 0x0c, // Payload Length = 12
(byte) 0x55, // Type = { 'U' } (URI)
// begin URI data within smart poster record #2
(byte) 0x01, // URI Prefix = 1 ("http://www.")
(byte) 0x6e, // 'n'
(byte) 0x78, // 'x'
(byte) 0x70, // 'p'
(byte) 0x2e, // '.'
(byte) 0x63, // 'c'
(byte) 0x6f, // 'o'
(byte) 0x6d, // 'm'
(byte) 0x2f, // '/'
(byte) 0x6e, // 'n'
(byte) 0x66, // 'f'
(byte) 0x63 // 'c'
// end URI data within smart poster record #2
// end smart poster record #2
// end smart poster payload
};
/**
* A Smart Poster containing a URL and no text. This message was created
* using the NXP reference phone.
*/
private static final byte[] SMART_POSTER_URL_NO_TEXT = new byte[] {
(byte) 0xd1, (byte) 0x02, (byte) 0x0f, (byte) 0x53, (byte) 0x70, (byte) 0xd1,
(byte) 0x01, (byte) 0x0b, (byte) 0x55, (byte) 0x01, (byte) 0x67, (byte) 0x6f,
(byte) 0x6f, (byte) 0x67, (byte) 0x6c, (byte) 0x65, (byte) 0x2e, (byte) 0x63,
(byte) 0x6f, (byte) 0x6d
};
/**
* A plain text tag in english. Generated using the NXP evaluation tool.
*/
private static final byte[] ENGLISH_PLAIN_TEXT = new byte[] {
(byte) 0xd1, (byte) 0x01, (byte) 0x1c, (byte) 0x54, (byte) 0x02, (byte) 0x65,
(byte) 0x6e, (byte) 0x53, (byte) 0x6f, (byte) 0x6d, (byte) 0x65, (byte) 0x20,
(byte) 0x72, (byte) 0x61, (byte) 0x6e, (byte) 0x64, (byte) 0x6f, (byte) 0x6d,
(byte) 0x20, (byte) 0x65, (byte) 0x6e, (byte) 0x67, (byte) 0x6c, (byte) 0x69,
(byte) 0x73, (byte) 0x68, (byte) 0x20, (byte) 0x74, (byte) 0x65, (byte) 0x78,
(byte) 0x74, (byte) 0x2e
};
/**
* Smart Poster containing a URL and Text. Generated using the NXP
* evaluation tool.
*/
private static final byte[] SMART_POSTER_URL_AND_TEXT = new byte[] {
(byte) 0xd1, (byte) 0x02, (byte) 0x1c, (byte) 0x53, (byte) 0x70, (byte) 0x91,
(byte) 0x01, (byte) 0x09, (byte) 0x54, (byte) 0x02, (byte) 0x65, (byte) 0x6e,
(byte) 0x47, (byte) 0x6f, (byte) 0x6f, (byte) 0x67, (byte) 0x6c, (byte) 0x65,
(byte) 0x51, (byte) 0x01, (byte) 0x0b, (byte) 0x55, (byte) 0x01, (byte) 0x67,
(byte) 0x6f, (byte) 0x6f, (byte) 0x67, (byte) 0x6c, (byte) 0x65, (byte) 0x2e,
(byte) 0x63, (byte) 0x6f, (byte) 0x6d
};
/**
* A plain URI. Generated using the NXP evaluation tool.
*/
private static final byte[] URI = new byte[] {
(byte) 0xd1, (byte) 0x01, (byte) 0x0b, (byte) 0x55, (byte) 0x01, (byte) 0x67,
(byte) 0x6f, (byte) 0x6f, (byte) 0x67, (byte) 0x6c, (byte) 0x65, (byte) 0x2e,
(byte) 0x63, (byte) 0x6f, (byte) 0x6d
};
/**
* A vcard. Generated using the NXP evaluation tool.
*/
private static final byte[] VCARD = new byte[] {
(byte) 0xc2, (byte) 0x0c, (byte) 0x00, (byte) 0x00, (byte) 0x01, (byte) 0x05,
(byte) 0x74, (byte) 0x65, (byte) 0x78, (byte) 0x74, (byte) 0x2f, (byte) 0x78,
(byte) 0x2d, (byte) 0x76, (byte) 0x43, (byte) 0x61, (byte) 0x72, (byte) 0x64,
(byte) 0x42, (byte) 0x45, (byte) 0x47, (byte) 0x49, (byte) 0x4e, (byte) 0x3a,
(byte) 0x56, (byte) 0x43, (byte) 0x41, (byte) 0x52, (byte) 0x44, (byte) 0x0d,
(byte) 0x0a, (byte) 0x56, (byte) 0x45, (byte) 0x52, (byte) 0x53, (byte) 0x49,
(byte) 0x4f, (byte) 0x4e, (byte) 0x3a, (byte) 0x33, (byte) 0x2e, (byte) 0x30,
(byte) 0x0d, (byte) 0x0a, (byte) 0x46, (byte) 0x4e, (byte) 0x3a, (byte) 0x4a,
(byte) 0x6f, (byte) 0x65, (byte) 0x20, (byte) 0x47, (byte) 0x6f, (byte) 0x6f,
(byte) 0x67, (byte) 0x6c, (byte) 0x65, (byte) 0x20, (byte) 0x45, (byte) 0x6d,
(byte) 0x70, (byte) 0x6c, (byte) 0x6f, (byte) 0x79, (byte) 0x65, (byte) 0x65,
(byte) 0x0d, (byte) 0x0a, (byte) 0x41, (byte) 0x44, (byte) 0x52, (byte) 0x3b,
(byte) 0x54, (byte) 0x59, (byte) 0x50, (byte) 0x45, (byte) 0x3d, (byte) 0x57,
(byte) 0x4f, (byte) 0x52, (byte) 0x4b, (byte) 0x3a, (byte) 0x3b, (byte) 0x3b,
(byte) 0x31, (byte) 0x36, (byte) 0x30, (byte) 0x30, (byte) 0x20, (byte) 0x41,
(byte) 0x6d, (byte) 0x70, (byte) 0x68, (byte) 0x69, (byte) 0x74, (byte) 0x68,
(byte) 0x65, (byte) 0x61, (byte) 0x74, (byte) 0x72, (byte) 0x65, (byte) 0x20,
(byte) 0x50, (byte) 0x61, (byte) 0x72, (byte) 0x6b, (byte) 0x77, (byte) 0x61,
(byte) 0x79, (byte) 0x3b, (byte) 0x39, (byte) 0x34, (byte) 0x30, (byte) 0x34,
(byte) 0x33, (byte) 0x20, (byte) 0x4d, (byte) 0x6f, (byte) 0x75, (byte) 0x6e,
(byte) 0x74, (byte) 0x61, (byte) 0x69, (byte) 0x6e, (byte) 0x20, (byte) 0x56,
(byte) 0x69, (byte) 0x65, (byte) 0x77, (byte) 0x0d, (byte) 0x0a, (byte) 0x54,
(byte) 0x45, (byte) 0x4c, (byte) 0x3b, (byte) 0x54, (byte) 0x59, (byte) 0x50,
(byte) 0x45, (byte) 0x3d, (byte) 0x50, (byte) 0x52, (byte) 0x45, (byte) 0x46,
(byte) 0x2c, (byte) 0x57, (byte) 0x4f, (byte) 0x52, (byte) 0x4b, (byte) 0x3a,
(byte) 0x36, (byte) 0x35, (byte) 0x30, (byte) 0x2d, (byte) 0x32, (byte) 0x35,
(byte) 0x33, (byte) 0x2d, (byte) 0x30, (byte) 0x30, (byte) 0x30, (byte) 0x30,
(byte) 0x0d, (byte) 0x0a, (byte) 0x45, (byte) 0x4d, (byte) 0x41, (byte) 0x49,
(byte) 0x4c, (byte) 0x3b, (byte) 0x54, (byte) 0x59, (byte) 0x50, (byte) 0x45,
(byte) 0x3d, (byte) 0x49, (byte) 0x4e, (byte) 0x54, (byte) 0x45, (byte) 0x52,
(byte) 0x4e, (byte) 0x45, (byte) 0x54, (byte) 0x3a, (byte) 0x73, (byte) 0x75,
(byte) 0x70, (byte) 0x70, (byte) 0x6f, (byte) 0x72, (byte) 0x74, (byte) 0x40,
(byte) 0x67, (byte) 0x6f, (byte) 0x6f, (byte) 0x67, (byte) 0x6c, (byte) 0x65,
(byte) 0x2e, (byte) 0x63, (byte) 0x6f, (byte) 0x6d, (byte) 0x0d, (byte) 0x0a,
(byte) 0x54, (byte) 0x49, (byte) 0x54, (byte) 0x4c, (byte) 0x45, (byte) 0x3a,
(byte) 0x53, (byte) 0x6f, (byte) 0x66, (byte) 0x74, (byte) 0x77, (byte) 0x61,
(byte) 0x72, (byte) 0x65, (byte) 0x20, (byte) 0x45, (byte) 0x6e, (byte) 0x67,
(byte) 0x69, (byte) 0x6e, (byte) 0x65, (byte) 0x65, (byte) 0x72, (byte) 0x0d,
(byte) 0x0a, (byte) 0x4f, (byte) 0x52, (byte) 0x47, (byte) 0x3a, (byte) 0x47,
(byte) 0x6f, (byte) 0x6f, (byte) 0x67, (byte) 0x6c, (byte) 0x65, (byte) 0x0d,
(byte) 0x0a, (byte) 0x55, (byte) 0x52, (byte) 0x4c, (byte) 0x3a, (byte) 0x68,
(byte) 0x74, (byte) 0x74, (byte) 0x70, (byte) 0x3a, (byte) 0x2f, (byte) 0x2f,
(byte) 0x77, (byte) 0x77, (byte) 0x77, (byte) 0x2e, (byte) 0x67, (byte) 0x6f,
(byte) 0x6f, (byte) 0x67, (byte) 0x6c, (byte) 0x65, (byte) 0x2e, (byte) 0x63,
(byte) 0x6f, (byte) 0x6d, (byte) 0x0d, (byte) 0x0a, (byte) 0x45, (byte) 0x4e,
(byte) 0x44, (byte) 0x3a, (byte) 0x56, (byte) 0x43, (byte) 0x41, (byte) 0x52,
(byte) 0x44, (byte) 0x0d, (byte) 0x0a
};
/**
* Send the text message "hello world" to a phone number. This was generated using
* the NXP reference phone.
*/
private static final byte[] SEND_TEXT_MESSAGE = new byte[] {
(byte) 0xd1, (byte) 0x02, (byte) 0x25, (byte) 0x53, (byte) 0x70, (byte) 0xd1,
(byte) 0x01, (byte) 0x21, (byte) 0x55, (byte) 0x00, (byte) 0x73, (byte) 0x6d,
(byte) 0x73, (byte) 0x3a, (byte) 0x31, (byte) 0x36, (byte) 0x35, (byte) 0x30,
(byte) 0x32, (byte) 0x35, (byte) 0x33, (byte) 0x30, (byte) 0x30, (byte) 0x30,
(byte) 0x30, (byte) 0x3f, (byte) 0x62, (byte) 0x6f, (byte) 0x64, (byte) 0x79,
(byte) 0x3d, (byte) 0x48, (byte) 0x65, (byte) 0x6c, (byte) 0x6c, (byte) 0x6f,
(byte) 0x20, (byte) 0x77, (byte) 0x6f, (byte) 0x72, (byte) 0x6c, (byte) 0x64
};
/**
* Call Google. Generated using the NXP reference phone.
*/
private static final byte[] CALL_GOOGLE = new byte[] {
(byte) 0xd1, (byte) 0x02, (byte) 0x10, (byte) 0x53, (byte) 0x70, (byte) 0xd1,
(byte) 0x01, (byte) 0x0c, (byte) 0x55, (byte) 0x05, (byte) 0x31, (byte) 0x36,
(byte) 0x35, (byte) 0x30, (byte) 0x32, (byte) 0x35, (byte) 0x33, (byte) 0x30,
(byte) 0x30, (byte) 0x30, (byte) 0x30
};
/**
* All the real ndef messages we've seen in the field.
*/
public static final byte[][] ALL_MOCK_MESSAGES = new byte[][] {
REAL_NFC_MSG, SMART_POSTER_URL_NO_TEXT, ENGLISH_PLAIN_TEXT,
SMART_POSTER_URL_AND_TEXT, URI, VCARD, SEND_TEXT_MESSAGE,
CALL_GOOGLE
};
}

View File

@@ -1,55 +0,0 @@
/*
* 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 android.net.Uri;
import android.nfc.NdefRecord;
import com.google.common.primitives.Bytes;
import java.nio.charset.Charsets;
/**
* Utilities for dealing with conversions to and from NdefRecords.
*
* TODO: Possibly move this class into core Android.
*/
public class NdefUtil {
private static final byte[] EMPTY = new byte[0];
/**
* Create a new {@link NdefRecord} containing the supplied {@link Uri}.
*/
public static NdefRecord toUriRecord(Uri uri) {
byte[] uriBytes = uri.toString().getBytes(Charsets.UTF_8);
/*
* We prepend 0x00 to the bytes of the URI to indicate that this
* is the entire URI, and we are not taking advantage of the
* URI shortening rules in the NFC Forum URI spec section 3.2.2.
* This produces a NdefRecord which is slightly larger than
* necessary.
*
* In the future, we should use the URI shortening rules in 3.2.2
* to create a smaller NdefRecord.
*/
byte[] payload = Bytes.concat(new byte[] { 0x00 }, uriBytes);
return new NdefRecord(NdefRecord.TNF_WELL_KNOWN,
NdefRecord.RTD_URI, EMPTY, payload);
}
}

View File

@@ -1,57 +0,0 @@
/*
* 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.TagDBHelper.NdefMessagesTable;
import android.content.Context;
import android.database.Cursor;
import android.text.format.DateUtils;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Adapter;
import android.widget.CursorAdapter;
import android.widget.TextView;
/**
* A custom {@link Adapter} that renders tag entries for a list.
*/
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) {
TextView mainLine = (TextView) view.findViewById(R.id.title);
TextView dateLine = (TextView) view.findViewById(R.id.date);
mainLine.setText(cursor.getString(cursor.getColumnIndex(NdefMessagesTable.TITLE)));
dateLine.setText(DateUtils.getRelativeTimeSpanString(
context, cursor.getLong(cursor.getColumnIndex(NdefMessagesTable.DATE))));
}
@Override
public View newView(Context context, Cursor cursor, ViewGroup parent) {
return mInflater.inflate(R.layout.tag_list_item, null);
}
}

View File

@@ -1,71 +0,0 @@
/*
* 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 android.app.Activity;
import android.app.TabActivity;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.res.Resources;
import android.os.Bundle;
import android.widget.TabHost;
/**
* A browsing {@link Activity} that displays the saved tags in categories under tabs.
*/
public class TagBrowserActivity extends TabActivity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Resources res = getResources();
TabHost tabHost = getTabHost();
tabHost.addTab(tabHost.newTabSpec("tags")
.setIndicator(getText(R.string.tab_tags),
res.getDrawable(R.drawable.ic_menu_tag))
.setContent(new Intent().setClass(this, TagList.class)));
tabHost.addTab(tabHost.newTabSpec("starred")
.setIndicator(getText(R.string.tab_starred),
res.getDrawable(R.drawable.ic_tab_starred))
.setContent(new Intent().setClass(this, TagList.class)
.putExtra(TagList.EXTRA_SHOW_STARRED_ONLY, true)));
}
@Override
public void onStart() {
super.onStart();
// Restore the last active tab
SharedPreferences prefs = getSharedPreferences("prefs", Context.MODE_PRIVATE);
getTabHost().setCurrentTabByTag(prefs.getString("tab", "tags"));
}
@Override
public void onStop() {
super.onStop();
// Save the active tab
SharedPreferences.Editor edit = getSharedPreferences("prefs", Context.MODE_PRIVATE).edit();
edit.putString("tab", getTabHost().getCurrentTabTag());
edit.apply();
}
}

View File

@@ -1,142 +0,0 @@
/*
* 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 android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.database.sqlite.SQLiteStatement;
import android.net.Uri;
import android.nfc.FormatException;
import android.nfc.NdefMessage;
import android.nfc.NdefRecord;
import java.util.Locale;
import com.android.apps.tag.message.NdefMessageParser;
import com.android.apps.tag.message.ParsedNdefMessage;
import com.google.common.annotations.VisibleForTesting;
/**
* Database utilities for the saved tags.
*/
public class TagDBHelper extends SQLiteOpenHelper {
private static final String DATABASE_NAME = "tags.db";
private static final int DATABASE_VERSION = 5;
public interface NdefMessagesTable {
public static final String TABLE_NAME = "nedf_msg";
public static final String _ID = "_id";
public static final String TITLE = "title";
public static final String BYTES = "bytes";
public static final String DATE = "date";
public static final String STARRED = "starred";
}
private static TagDBHelper sInstance;
private Context mContext;
public static synchronized TagDBHelper getInstance(Context context) {
if (sInstance == null) {
sInstance = new TagDBHelper(context.getApplicationContext());
}
return sInstance;
}
private TagDBHelper(Context context) {
this(context, DATABASE_NAME);
mContext = context;
}
@VisibleForTesting
TagDBHelper(Context context, String dbFile) {
super(context, dbFile, null, DATABASE_VERSION);
mContext = context;
}
@Override
public void onCreate(SQLiteDatabase db) {
db.execSQL("CREATE TABLE " + NdefMessagesTable.TABLE_NAME + " (" +
NdefMessagesTable._ID + " INTEGER PRIMARY KEY AUTOINCREMENT, " +
NdefMessagesTable.TITLE + " TEXT NOT NULL DEFAULT ''," +
NdefMessagesTable.BYTES + " BLOB NOT NULL, " +
NdefMessagesTable.DATE + " INTEGER NOT NULL, " +
NdefMessagesTable.STARRED + " INTEGER NOT NULL DEFAULT 0" + // boolean
");");
db.execSQL("CREATE INDEX msgIndex ON " + NdefMessagesTable.TABLE_NAME + " (" +
NdefMessagesTable.DATE + " DESC, " +
NdefMessagesTable.STARRED + " ASC" +
")");
addTestData(db);
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
// Drop everything and recreate it for now
db.execSQL("DROP TABLE IF EXISTS " + NdefMessagesTable.TABLE_NAME);
onCreate(db);
}
private void addTestData(SQLiteDatabase db) {
// A fake message containing 1 URL
NdefMessage msg1 = new NdefMessage(new NdefRecord[] {
NdefUtil.toUriRecord(Uri.parse("http://www.google.com"))
});
// A fake message containing 2 URLs
NdefMessage msg2 = new NdefMessage(new NdefRecord[] {
NdefUtil.toUriRecord(Uri.parse("http://www.youtube.com")),
NdefUtil.toUriRecord(Uri.parse("http://www.android.com"))
});
insertNdefMessage(db, msg1, false);
insertNdefMessage(db, msg2, true);
try {
// insert some real messages we found in the field.
for (byte[] msg : MockNdefMessages.ALL_MOCK_MESSAGES) {
NdefMessage msg3 = new NdefMessage(msg);
insertNdefMessage(db, msg3, false);
}
} catch (FormatException e) {
throw new RuntimeException(e);
}
}
public void insertNdefMessage(SQLiteDatabase db, NdefMessage msg, boolean isStarred) {
ParsedNdefMessage parsedMsg = NdefMessageParser.parse(msg);
SQLiteStatement stmt = null;
try {
stmt = db.compileStatement("INSERT INTO " + NdefMessagesTable.TABLE_NAME +
"(" + NdefMessagesTable.BYTES + ", " + NdefMessagesTable.DATE + ", " +
NdefMessagesTable.STARRED + "," + NdefMessagesTable.TITLE + ") " +
"values (?, ?, ?, ?)");
stmt.bindBlob(1, msg.toByteArray());
stmt.bindLong(2, System.currentTimeMillis());
stmt.bindLong(3, isStarred ? 1 : 0);
stmt.bindString(4, parsedMsg.getSnippet(mContext, Locale.getDefault()));
stmt.executeInsert();
} finally {
if (stmt != null) stmt.close();
}
}
}

View File

@@ -1,132 +0,0 @@
/*
* 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 android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.app.ListActivity;
import android.content.DialogInterface;
import android.content.Intent;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.nfc.FormatException;
import android.nfc.NdefMessage;
import android.os.AsyncTask;
import android.os.Bundle;
import android.util.Log;
import android.view.Menu;
import android.view.View;
import android.widget.ListView;
import com.android.apps.tag.TagDBHelper.NdefMessagesTable;
/**
* An {@link Activity} that displays a flat list of tags that can be "opened".
*/
public class TagList extends ListActivity implements DialogInterface.OnClickListener {
static final String TAG = "TagList";
static final String EXTRA_SHOW_STARRED_ONLY = "show_starred_only";
SQLiteDatabase mDatabase;
TagAdapter mAdapter;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
boolean showStarredOnly = getIntent().getBooleanExtra(EXTRA_SHOW_STARRED_ONLY, false);
mDatabase = TagDBHelper.getInstance(this).getReadableDatabase();
String selection = showStarredOnly ? NdefMessagesTable.STARRED + "=1" : null;
new TagLoaderTask().execute(selection);
mAdapter = new TagAdapter(this);
setListAdapter(mAdapter);
registerForContextMenu(getListView());
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
super.onCreateOptionsMenu(menu);
menu.add("hello world");
return true;
}
@Override
protected Dialog onCreateDialog(int id, Bundle args) {
String[] stuff = new String[] { "a", "b" };
return new AlertDialog.Builder(this)
.setTitle("blah")
.setItems(stuff, this)
.setPositiveButton("Delete", null)
.setNegativeButton("Cancel", null)
.create();
}
@Override
protected void onDestroy() {
if (mAdapter != null) {
mAdapter.changeCursor(null);
}
super.onDestroy();
}
@Override
protected void onListItemClick(ListView l, View v, int position, long id) {
Cursor cursor = mAdapter.getCursor();
cursor.moveToPosition(position);
byte[] tagBytes = cursor.getBlob(cursor.getColumnIndexOrThrow(NdefMessagesTable.BYTES));
try {
NdefMessage msg = new NdefMessage(tagBytes);
Intent intent = new Intent(this, TagViewer.class);
intent.putExtra(TagViewer.EXTRA_MESSAGE, msg);
intent.putExtra(TagViewer.EXTRA_TAG_DB_ID, id);
startActivity(intent);
} catch (FormatException e) {
Log.e(TAG, "bad format for tag " + id + ": " + tagBytes, e);
return;
}
}
@Override
public void onClick(DialogInterface dialog, int which) {
}
final class TagLoaderTask extends AsyncTask<String, Void, Cursor> {
@Override
public Cursor doInBackground(String... args) {
String selection = args[0];
Cursor cursor = mDatabase.query(
NdefMessagesTable.TABLE_NAME,
new String[] {
NdefMessagesTable._ID,
NdefMessagesTable.BYTES,
NdefMessagesTable.DATE,
NdefMessagesTable.TITLE },
selection,
null, null, null, NdefMessagesTable.DATE + " DESC");
cursor.getCount();
return cursor;
}
@Override
protected void onPostExecute(Cursor cursor) {
mAdapter.changeCursor(cursor);
}
}
}

View File

@@ -1,58 +0,0 @@
/*
* 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.TagDBHelper.NdefMessagesTable;
import android.app.IntentService;
import android.content.Intent;
import android.database.sqlite.SQLiteDatabase;
import android.nfc.NdefMessage;
import android.os.Parcelable;
public class TagService extends IntentService {
public static final String EXTRA_SAVE_MSGS = "msgs";
public static final String EXTRA_DELETE_ID = "delete";
public TagService() {
super("SaveTagService");
}
@Override
public void onHandleIntent(Intent intent) {
TagDBHelper helper = TagDBHelper.getInstance(this);
SQLiteDatabase db = helper.getWritableDatabase();
if (intent.hasExtra(EXTRA_SAVE_MSGS)) {
Parcelable[] parcels = intent.getParcelableArrayExtra(EXTRA_SAVE_MSGS);
db.beginTransaction();
try {
for (Parcelable parcel : parcels) {
helper.insertNdefMessage(db, (NdefMessage) parcel, false);
}
db.setTransactionSuccessful();
} finally {
db.endTransaction();
}
return;
} else if (intent.hasExtra(EXTRA_DELETE_ID)) {
long id = intent.getLongExtra(EXTRA_DELETE_ID, 0);
db.delete(NdefMessagesTable.TABLE_NAME, NdefMessagesTable._ID + "=?",
new String[] { Long.toString(id) });
return;
}
}
}

View File

@@ -1,189 +0,0 @@
/*
* 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.message.NdefMessageParser;
import com.android.apps.tag.message.ParsedNdefMessage;
import com.android.apps.tag.record.ParsedNdefRecord;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.nfc.NdefMessage;
import android.nfc.NdefTag;
import android.nfc.NfcAdapter;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.text.TextUtils;
import android.util.Log;
import android.view.ContextThemeWrapper;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.WindowManager;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import java.util.Locale;
/**
* An {@link Activity} which handles a broadcast of a new tag that the device just discovered.
*/
public class TagViewer extends Activity implements OnClickListener, Handler.Callback {
static final String TAG = "SaveTag";
static final String EXTRA_TAG_DB_ID = "db_id";
static final String EXTRA_MESSAGE = "msg";
/** This activity will finish itself in this amount of time if the user doesn't do anything. */
static final int ACTIVITY_TIMEOUT_MS = 10 * 1000;
long mTagDatabaseId;
ImageView mIcon;
TextView mTitle;
CheckBox mStar;
Button mDeleteButton;
Button mCancelButton;
NdefMessage[] mMessagesToSave = null;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED
| WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD
| WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON
| WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON
| WindowManager.LayoutParams.FLAG_ALLOW_LOCK_WHILE_SCREEN_ON
| WindowManager.LayoutParams.FLAG_DIM_BEHIND
);
setContentView(R.layout.tag_viewer);
mTitle = (TextView) findViewById(R.id.title);
mIcon = (ImageView) findViewById(R.id.icon);
mStar = (CheckBox) findViewById(R.id.star);
mDeleteButton = (Button) findViewById(R.id.btn_delete);
mCancelButton = (Button) findViewById(R.id.btn_cancel);
mDeleteButton.setOnClickListener(this);
mCancelButton.setOnClickListener(this);
mIcon.setImageResource(R.drawable.ic_launcher_nfc);
Intent intent = getIntent();
NdefMessage[] msgs = null;
NdefTag tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
if (tag == null) {
// Maybe it came from the database?
mTagDatabaseId = intent.getLongExtra(EXTRA_TAG_DB_ID, -1);
NdefMessage msg = intent.getParcelableExtra(EXTRA_MESSAGE);
if (msg != null) {
msgs = new NdefMessage[] { msg };
}
// Hide the text about saving the tag, it's already in the database
findViewById(R.id.cancel_help_text).setVisibility(View.GONE);
} else {
msgs = tag.getNdefMessages();
mDeleteButton.setVisibility(View.GONE);
// Set a timer on this activity since it wasn't created by the user
new Handler(this).sendEmptyMessageDelayed(0, ACTIVITY_TIMEOUT_MS);
// Save the messages that were just scanned
mMessagesToSave = msgs;
}
if (msgs == null || msgs.length == 0) {
Log.e(TAG, "No NDEF messages");
finish();
return;
}
Context contentContext = new ContextThemeWrapper(this, android.R.style.Theme_Light);
LayoutInflater inflater = LayoutInflater.from(contentContext);
LinearLayout list = (LinearLayout) findViewById(R.id.list);
buildTagViews(list, inflater, msgs);
if (TextUtils.isEmpty(getTitle())) {
// There isn't a snippet for this tag, use a default title
setTitle(R.string.tag_unknown);
}
}
private void buildTagViews(LinearLayout list, LayoutInflater inflater, NdefMessage[] msgs) {
if (msgs == null || msgs.length == 0) {
return;
}
// Build the views from the logical records in the messages
NdefMessage msg = msgs[0];
// Set the title to be the snippet of the message
ParsedNdefMessage parsedMsg = NdefMessageParser.parse(msg);
setTitle(parsedMsg.getSnippet(this, Locale.getDefault()));
// Build views for all of the sub records
for (ParsedNdefRecord record : parsedMsg.getRecords()) {
list.addView(record.getView(this, inflater, list));
inflater.inflate(R.layout.tag_divider, list, true);
}
}
@Override
public void setTitle(CharSequence title) {
mTitle.setText(title);
}
@Override
public void onClick(View view) {
if (view == mDeleteButton) {
Intent save = new Intent(this, TagService.class);
save.putExtra(TagService.EXTRA_DELETE_ID, mTagDatabaseId);
startService(save);
finish();
} else if (view == mCancelButton) {
mMessagesToSave = null;
finish();
}
}
@Override
public void onStop() {
super.onStop();
if (mMessagesToSave != null) {
saveMessages(mMessagesToSave);
}
}
void saveMessages(NdefMessage[] msgs) {
Intent save = new Intent(this, TagService.class);
save.putExtra(TagService.EXTRA_SAVE_MSGS, msgs);
startService(save);
}
@Override
public boolean handleMessage(Message msg) {
finish();
return true;
}
}

View File

@@ -1,45 +0,0 @@
/*
* 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.message;
import com.android.apps.tag.R;
import com.android.apps.tag.record.ParsedNdefRecord;
import android.content.Context;
import java.util.ArrayList;
import java.util.Locale;
/**
* A parsed message containing no elements.
*/
class EmptyMessage extends ParsedNdefMessage {
/* package private */ EmptyMessage() {
super(new ArrayList<ParsedNdefRecord>());
}
@Override
public String getSnippet(Context context, Locale locale) {
return context.getString(R.string.tag_empty);
}
@Override
public boolean isStarred() {
return false;
}
}

View File

@@ -1,76 +0,0 @@
/*
* 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.message;
import android.nfc.NdefMessage;
import android.nfc.NdefRecord;
import com.android.apps.tag.record.ParsedNdefRecord;
import com.android.apps.tag.record.SmartPoster;
import com.android.apps.tag.record.TextRecord;
import com.android.apps.tag.record.UriRecord;
import java.util.ArrayList;
import java.util.List;
/**
* Utility class for creating {@link ParsedNdefMessage}s.
*/
public class NdefMessageParser {
// Utility class
private NdefMessageParser() { }
/** Parse an NdefMessage */
public static ParsedNdefMessage parse(NdefMessage message) {
List<ParsedNdefRecord> elements = getRecords(message);
if (elements.isEmpty()) {
return new EmptyMessage();
}
ParsedNdefRecord first = elements.get(0);
if (elements.size() == 1) {
if (first instanceof SmartPoster) {
return new SmartPosterMessage((SmartPoster) first, elements);
}
if (first instanceof TextRecord) {
return new TextMessage((TextRecord) first, elements);
}
if (first instanceof UriRecord) {
return new UriMessage((UriRecord) first, elements);
}
}
return new UnknownMessage(elements);
}
public static List<ParsedNdefRecord> getRecords(NdefMessage message) {
List<ParsedNdefRecord> elements = new ArrayList<ParsedNdefRecord>();
for (NdefRecord record : message.getRecords()) {
if (UriRecord.isUri(record)) {
elements.add(UriRecord.parse(record));
} else if (TextRecord.isText(record)) {
elements.add(TextRecord.parse(record));
} else if (SmartPoster.isPoster(record)) {
elements.add(SmartPoster.parse(record));
}
}
return elements;
}
}

View File

@@ -1,54 +0,0 @@
/*
* 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.message;
import com.android.apps.tag.record.ParsedNdefRecord;
import com.google.common.collect.ImmutableList;
import android.content.Context;
import java.util.List;
import java.util.Locale;
/**
* A parsed version of an {@link android.nfc.NdefMessage}
*/
public abstract class ParsedNdefMessage {
private List<ParsedNdefRecord> mRecords;
public ParsedNdefMessage(List<ParsedNdefRecord> records) {
mRecords = ImmutableList.copyOf(records);
}
/**
* Returns the list of parsed records on this message.
*/
public List<ParsedNdefRecord> getRecords() {
return mRecords;
}
/**
* Returns the snippet information associated with the NdefMessage
* most appropriate for the given {@code locale}.
*/
public abstract String getSnippet(Context context, Locale locale);
// TODO: Determine if this is the best place for holding whether
// the user has starred this parsed message.
public abstract boolean isStarred();
}

View File

@@ -1,53 +0,0 @@
/*
* 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.message;
import com.android.apps.tag.record.ParsedNdefRecord;
import com.android.apps.tag.record.SmartPoster;
import com.android.apps.tag.record.TextRecord;
import com.google.common.base.Preconditions;
import android.content.Context;
import java.util.List;
import java.util.Locale;
/**
* A message consisting of one {@link SmartPoster} object.
*/
class SmartPosterMessage extends ParsedNdefMessage {
private final SmartPoster mPoster;
SmartPosterMessage(SmartPoster poster, List<ParsedNdefRecord> records) {
super(Preconditions.checkNotNull(records));
mPoster = Preconditions.checkNotNull(poster);
}
@Override
public String getSnippet(Context context, Locale locale) {
TextRecord title = mPoster.getTitle();
if (title == null) {
return mPoster.getUriRecord().getPrettyUriString(context);
}
return title.getText();
}
@Override
public boolean isStarred() {
return false;
}
}

View File

@@ -1,48 +0,0 @@
/*
* 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.message;
import com.android.apps.tag.record.ParsedNdefRecord;
import com.android.apps.tag.record.TextRecord;
import com.google.common.base.Preconditions;
import android.content.Context;
import java.util.List;
import java.util.Locale;
/**
* A message containing one text element
*/
class TextMessage extends ParsedNdefMessage {
private final TextRecord mRecord;
TextMessage(TextRecord record, List<ParsedNdefRecord> records) {
super(Preconditions.checkNotNull(records));
mRecord = Preconditions.checkNotNull(record);
}
@Override
public String getSnippet(Context context, Locale locale) {
return mRecord.getText();
}
@Override
public boolean isStarred() {
return false;
}
}

View File

@@ -1,46 +0,0 @@
/*
* 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.message;
import com.android.apps.tag.R;
import com.android.apps.tag.record.ParsedNdefRecord;
import com.google.common.base.Preconditions;
import android.content.Context;
import java.util.List;
import java.util.Locale;
/**
* The catchall parsed message format for when nothing else better applies.
*/
class UnknownMessage extends ParsedNdefMessage {
UnknownMessage(List<ParsedNdefRecord> records) {
super(Preconditions.checkNotNull(records));
}
@Override
public String getSnippet(Context context, Locale locale) {
return context.getString(R.string.tag_unknown);
}
@Override
public boolean isStarred() {
return false;
}
}

View File

@@ -1,50 +0,0 @@
/*
* 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.message;
import com.android.apps.tag.record.ParsedNdefRecord;
import com.android.apps.tag.record.UriRecord;
import com.google.common.base.Preconditions;
import android.content.Context;
import java.util.List;
import java.util.Locale;
/**
* A {@link ParsedNdefMessage} consisting of one {@link UriRecord}.
*/
class UriMessage extends ParsedNdefMessage {
private final UriRecord mRecord;
UriMessage(UriRecord record, List<ParsedNdefRecord> records) {
super(Preconditions.checkNotNull(records));
mRecord = Preconditions.checkNotNull(record);
}
@Override
public String getSnippet(Context context, Locale locale) {
// URIs cannot be localized
return mRecord.getPrettyUriString(context);
}
@Override
public boolean isStarred() {
return false;
}
}

View File

@@ -1,36 +0,0 @@
/*
* 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.record;
import android.app.Activity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
/**
* TODO: come up with a better name.
*/
public interface ParsedNdefRecord {
// Just a placeholder for now. Probably not needed nor desired.
public String getRecordType();
/**
* Returns a view to display this record.
*/
public View getView(Activity activity, LayoutInflater inflater, ViewGroup parent);
}

View File

@@ -1,136 +0,0 @@
/*
* 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.record;
import com.android.apps.tag.R;
import com.android.apps.tag.message.NdefMessageParser;
import com.google.common.base.Preconditions;
import com.google.common.collect.Iterables;
import android.app.Activity;
import android.nfc.FormatException;
import android.nfc.NdefMessage;
import android.nfc.NdefRecord;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewGroup.LayoutParams;
import android.widget.LinearLayout;
import android.widget.TextView;
import java.util.Arrays;
import java.util.NoSuchElementException;
import javax.annotation.Nullable;
/**
* A representation of an NFC Forum "Smart Poster".
*/
public class SmartPoster implements ParsedNdefRecord {
/**
* NFC Forum Smart Poster Record Type Definition section 3.2.1.
*
* "The Title record for the service (there can be many of these in
* different languages, but a language MUST NOT be repeated).
* This record is optional."
*/
private final TextRecord mTitleRecord;
/**
* NFC Forum Smart Poster Record Type Definition section 3.2.1.
*
* "The URI record. This is the core of the Smart Poster, and all other
* records are just metadata about this record. There MUST be one URI
* record and there MUST NOT be more than one."
*/
private final UriRecord mUriRecord;
private SmartPoster(UriRecord uri, @Nullable TextRecord title) {
mUriRecord = Preconditions.checkNotNull(uri);
mTitleRecord = title;
}
public UriRecord getUriRecord() {
return mUriRecord;
}
/**
* Returns the title of the smart poster. This may be {@code null}.
*/
public TextRecord getTitle() {
return mTitleRecord;
}
public static SmartPoster parse(NdefRecord record) {
Preconditions.checkArgument(record.getTnf() == NdefRecord.TNF_WELL_KNOWN);
Preconditions.checkArgument(Arrays.equals(record.getType(), NdefRecord.RTD_SMART_POSTER));
try {
NdefMessage subRecords = new NdefMessage(record.getPayload());
Iterable<ParsedNdefRecord> records = NdefMessageParser.getRecords(subRecords);
UriRecord uri = Iterables.getOnlyElement(Iterables.filter(records, UriRecord.class));
Iterable<TextRecord> textFields = Iterables.filter(records, TextRecord.class);
TextRecord title = null;
if (!Iterables.isEmpty(textFields)) {
title = Iterables.get(textFields, 0);
}
return new SmartPoster(uri, title);
} catch (FormatException e) {
throw new IllegalArgumentException(e);
} catch (NoSuchElementException e) {
throw new IllegalArgumentException(e);
}
}
public static boolean isPoster(NdefRecord record) {
try {
parse(record);
return true;
} catch (IllegalArgumentException e) {
return false;
}
}
@Override
public String getRecordType() {
return "SmartPoster";
}
@Override
public View getView(Activity activity, LayoutInflater inflater, ViewGroup parent) {
if (mTitleRecord != null) {
// Build a container to hold the title and the URI
LinearLayout container = new LinearLayout(activity);
container.setOrientation(LinearLayout.VERTICAL);
container.setLayoutParams(new LayoutParams(
LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT));
container.addView(mTitleRecord.getView(activity, inflater, container));
inflater.inflate(R.layout.tag_divider, container);
container.addView(mUriRecord.getView(activity, inflater, container));
return container;
} else {
// Just a URI, return a view for it directly
return mUriRecord.getView(activity, inflater, parent);
}
}
}

View File

@@ -1,117 +0,0 @@
/*
* 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.record;
import com.android.apps.tag.R;
import com.google.common.base.Preconditions;
import android.app.Activity;
import android.nfc.NdefRecord;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import java.io.UnsupportedEncodingException;
import java.util.Arrays;
/**
* An NFC Text Record
*/
public class TextRecord implements ParsedNdefRecord {
/** ISO/IANA language code */
private final String mLanguageCode;
private final String mText;
private TextRecord(String languageCode, String text) {
mLanguageCode = Preconditions.checkNotNull(languageCode);
mText = Preconditions.checkNotNull(text);
}
@Override
public String getRecordType() {
return "Text";
}
@Override
public View getView(Activity activity, LayoutInflater inflater, ViewGroup parent) {
TextView text = (TextView) inflater.inflate(R.layout.tag_text, parent, false);
text.setText(mText);
return text;
}
public String getText() {
return mText;
}
/**
* Returns the ISO/IANA language code associated with this text element.
*
* TODO: this should return a {@link java.util.Locale}
*/
public String getLanguageCode() {
return mLanguageCode;
}
// TODO: deal with text fields which span multiple NdefRecords
public static TextRecord parse(NdefRecord record) {
Preconditions.checkArgument(record.getTnf() == NdefRecord.TNF_WELL_KNOWN);
Preconditions.checkArgument(Arrays.equals(record.getType(), NdefRecord.RTD_TEXT));
try {
byte[] payload = record.getPayload();
/*
* payload[0] contains the "Status Byte Encodings" field, per
* the NFC Forum "Text Record Type Definition" section 3.2.1.
*
* bit7 is the Text Encoding Field.
*
* if (Bit_7 == 0): The text is encoded in UTF-8
* if (Bit_7 == 1): The text is encoded in UTF16
*
* Bit_6 is reserved for future use and must be set to zero.
*
* Bits 5 to 0 are the length of the IANA language code.
*/
String textEncoding = ((payload[0] & 0200) == 0) ? "UTF-8" : "UTF-16";
int languageCodeLength = payload[0] & 0077;
String languageCode = new String(payload, 1, languageCodeLength, "US-ASCII");
String text = new String(payload,
languageCodeLength + 1,
payload.length - languageCodeLength - 1,
textEncoding);
return new TextRecord(languageCode, text);
} catch (UnsupportedEncodingException e) {
// should never happen unless we get a malformed tag.
throw new IllegalArgumentException(e);
}
}
public static boolean isText(NdefRecord record) {
try {
parse(record);
return true;
} catch (IllegalArgumentException e) {
return false;
}
}
}

View File

@@ -1,252 +0,0 @@
/*
* 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.record;
import com.android.apps.tag.R;
import com.google.common.base.Preconditions;
import com.google.common.collect.BiMap;
import com.google.common.collect.ImmutableBiMap;
import com.google.common.primitives.Bytes;
import android.app.Activity;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.net.Uri;
import android.nfc.NdefRecord;
import android.telephony.PhoneNumberUtils;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.view.ViewGroup.LayoutParams;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import java.nio.charset.Charsets;
import java.util.Arrays;
import java.util.List;
/**
* A parsed record containing a Uri.
*/
public class UriRecord implements ParsedNdefRecord, OnClickListener {
private static final class ClickInfo {
public Activity activity;
public Intent intent;
public ClickInfo(Activity activity, Intent intent) {
this.activity = activity;
this.intent = intent;
}
}
/**
* NFC Forum "URI Record Type Definition"
*
* This is a mapping of "URI Identifier Codes" to URI string prefixes,
* per section 3.2.2 of the NFC Forum URI Record Type Definition document.
*/
private static final BiMap<Byte, String> URI_PREFIX_MAP = ImmutableBiMap.<Byte, String>builder()
.put((byte) 0x00, "")
.put((byte) 0x01, "http://www.")
.put((byte) 0x02, "https://www.")
.put((byte) 0x03, "http://")
.put((byte) 0x04, "https://")
.put((byte) 0x05, "tel:")
.put((byte) 0x06, "mailto:")
.put((byte) 0x07, "ftp://anonymous:anonymous@")
.put((byte) 0x08, "ftp://ftp.")
.put((byte) 0x09, "ftps://")
.put((byte) 0x0A, "sftp://")
.put((byte) 0x0B, "smb://")
.put((byte) 0x0C, "nfs://")
.put((byte) 0x0D, "ftp://")
.put((byte) 0x0E, "dav://")
.put((byte) 0x0F, "news:")
.put((byte) 0x10, "telnet://")
.put((byte) 0x11, "imap:")
.put((byte) 0x12, "rtsp://")
.put((byte) 0x13, "urn:")
.put((byte) 0x14, "pop:")
.put((byte) 0x15, "sip:")
.put((byte) 0x16, "sips:")
.put((byte) 0x17, "tftp:")
.put((byte) 0x18, "btspp://")
.put((byte) 0x19, "btl2cap://")
.put((byte) 0x1A, "btgoep://")
.put((byte) 0x1B, "tcpobex://")
.put((byte) 0x1C, "irdaobex://")
.put((byte) 0x1D, "file://")
.put((byte) 0x1E, "urn:epc:id:")
.put((byte) 0x1F, "urn:epc:tag:")
.put((byte) 0x20, "urn:epc:pat:")
.put((byte) 0x21, "urn:epc:raw:")
.put((byte) 0x22, "urn:epc:")
.put((byte) 0x23, "urn:nfc:")
.build();
private final Uri mUri;
private UriRecord(Uri uri) {
this.mUri = Preconditions.checkNotNull(uri);
}
@Override
public String getRecordType() {
return "Uri";
}
public Intent getIntentForUri() {
String scheme = mUri.getScheme();
if ("tel".equals(scheme)) {
return new Intent(Intent.ACTION_CALL, mUri);
} else if ("sms".equals(scheme) || "smsto".equals(scheme)) {
return new Intent(Intent.ACTION_SENDTO, mUri);
} else {
return new Intent(Intent.ACTION_VIEW, mUri);
}
}
public String getPrettyUriString(Context context) {
String scheme = mUri.getScheme();
boolean tel = "tel".equals(scheme);
boolean sms = "sms".equals(scheme) || "smsto".equals(scheme);
if (tel || sms) {
String ssp = mUri.getSchemeSpecificPart();
int offset = ssp.indexOf('?');
if (offset >= 0) {
ssp = ssp.substring(0, offset);
}
if (tel) {
return context.getString(R.string.action_call, PhoneNumberUtils.formatNumber(ssp));
} else {
return context.getString(R.string.action_text, PhoneNumberUtils.formatNumber(ssp));
}
} else {
return mUri.toString();
}
}
@Override
public View getView(Activity activity, LayoutInflater inflater, ViewGroup parent) {
Intent intent = getIntentForUri();
PackageManager pm = activity.getPackageManager();
List<ResolveInfo> activities = pm.queryIntentActivities(intent, 0);
int numActivities = activities.size();
if (numActivities == 0) {
TextView text = (TextView) inflater.inflate(R.layout.tag_text, parent, false);
text.setText(mUri.toString());
return text;
} else if (numActivities == 1) {
return buildActivityView(activity, activities.get(0), pm, inflater, parent);
} else {
// Build a container to hold the multiple entries
LinearLayout container = new LinearLayout(activity);
container.setOrientation(LinearLayout.VERTICAL);
container.setLayoutParams(new LayoutParams(
LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT));
// Create an entry for each activity that can handle the URI
for (ResolveInfo resolveInfo : activities) {
if (container.getChildCount() > 0) {
inflater.inflate(R.layout.tag_divider, container);
}
container.addView(buildActivityView(activity, resolveInfo, pm, inflater, container));
}
return container;
}
}
private View buildActivityView(Activity activity, ResolveInfo resolveInfo, PackageManager pm,
LayoutInflater inflater, ViewGroup parent) {
Intent intent = getIntentForUri();
ActivityInfo activityInfo = resolveInfo.activityInfo;
intent.setComponent(new ComponentName(activityInfo.packageName, activityInfo.name));
View item = inflater.inflate(R.layout.tag_uri, parent, false);
item.setOnClickListener(this);
item.setTag(new ClickInfo(activity, intent));
ImageView icon = (ImageView) item.findViewById(R.id.icon);
icon.setImageDrawable(resolveInfo.loadIcon(pm));
TextView text = (TextView) item.findViewById(R.id.secondary);
text.setText(resolveInfo.loadLabel(pm));
text = (TextView) item.findViewById(R.id.primary);
text.setText(getPrettyUriString(activity));
return item;
}
@Override
public void onClick(View view) {
ClickInfo info = (ClickInfo) view.getTag();
info.activity.startActivity(info.intent);
info.activity.finish();
}
public Uri getUri() {
return mUri;
}
/**
* Convert {@link android.nfc.NdefRecord} into a {@link android.net.Uri}.
*
* TODO: This class does not handle NdefRecords where the TNF
* (Type Name Format) of the class is {@link android.nfc.NdefRecord#TNF_ABSOLUTE_URI}.
* This should be fixed.
*
* @throws IllegalArgumentException if the NdefRecord is not a
* record containing a URI.
*/
public static UriRecord parse(NdefRecord record) {
Preconditions.checkArgument(record.getTnf() == NdefRecord.TNF_WELL_KNOWN);
Preconditions.checkArgument(Arrays.equals(record.getType(), NdefRecord.RTD_URI));
byte[] payload = record.getPayload();
/*
* payload[0] contains the URI Identifier Code, per the
* NFC Forum "URI Record Type Definition" section 3.2.2.
*
* payload[1]...payload[payload.length - 1] contains the rest of
* the URI.
*/
String prefix = URI_PREFIX_MAP.get(payload[0]);
byte[] fullUri = Bytes.concat(
prefix.getBytes(Charsets.UTF_8),
Arrays.copyOfRange(payload, 1, payload.length));
return new UriRecord(Uri.parse(new String(fullUri, Charsets.UTF_8)));
}
public static boolean isUri(NdefRecord record) {
try {
parse(record);
return true;
} catch (IllegalArgumentException e) {
return false;
}
}
}

View File

@@ -1,14 +0,0 @@
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_SRC_FILES := $(call all-subdir-java-files)
LOCAL_JAVA_LIBRARIES := android.test.runner
LOCAL_PACKAGE_NAME := TagAppTests
LOCAL_MODULE_TAGS := tests
LOCAL_INSTRUMENTATION_FOR := TagApp
include $(BUILD_PACKAGE)

View File

@@ -1,32 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- 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.
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.apps.tag.tests">
<!-- We add an application tag here just so that we can indicate that
this package needs to link against the android.test library,
which is needed when building test cases. -->
<application>
<uses-library android:name="android.test.runner" />
</application>
<instrumentation android:name="android.test.InstrumentationTestRunner"
android:targetPackage="com.android.apps.tag"
android:label="Tag tests">
</instrumentation>
</manifest>

View File

@@ -1 +0,0 @@
tested.project.dir=..

View File

@@ -1,53 +0,0 @@
/*
* 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 android.nfc.NdefRecord;
import android.test.AndroidTestCase;
import com.android.apps.tag.record.TextRecord;
import com.google.common.primitives.Bytes;
import java.io.UnsupportedEncodingException;
public class NdefUtilTest extends AndroidTestCase {
public void testToText() throws UnsupportedEncodingException {
checkWord("Hello", "en-US", true);
checkWord("Hello", "en-US", false);
checkWord("abc\\u5639\\u563b", "cp1251", true);
checkWord("abc\\u5639\\u563b", "cp1251", false);
}
private static void checkWord(String word, String encoding, boolean isUtf8) throws UnsupportedEncodingException {
String utfEncoding = isUtf8 ? "UTF-8" : "UTF-16";
byte[] encodingBytes = encoding.getBytes("US-ASCII");
byte[] text = word.getBytes(utfEncoding);
int utfBit = isUtf8 ? 0 : (1 << 7);
char status = (char) (utfBit + encodingBytes.length);
byte[] data = Bytes.concat(
new byte[] { (byte) status },
encodingBytes,
text
);
NdefRecord record = new NdefRecord(NdefRecord.TNF_WELL_KNOWN, NdefRecord.RTD_TEXT, new byte[0], data);
assertEquals(word, TextRecord.parse(record).getText());
}
}

View File

@@ -1,35 +0,0 @@
/*
* 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 android.nfc.NdefMessage;
import android.test.AndroidTestCase;
import com.android.apps.tag.record.SmartPoster;
/**
* Tests for {@link SmartPoster}.
*/
public class SmartPosterTest extends AndroidTestCase {
public void testSmartPoster() throws Exception {
NdefMessage msg = new NdefMessage(MockNdefMessages.REAL_NFC_MSG);
SmartPoster poster = SmartPoster.parse(msg.getRecords()[0]);
assertEquals("NFC Forum Type 4 Tag", poster.getTitle().getText());
assertEquals("http://www.nxp.com/nfc", poster.getUriRecord().getUri().toString());
}
}

View File

@@ -1,41 +0,0 @@
/*
* 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 android.test.ActivityInstrumentationTestCase2;
/**
* Make sure that the main launcher activity opens up properly, which will be
* verified by {@link #testActivityTestCaseSetUpProperly}.
*/
public class TagsTest extends ActivityInstrumentationTestCase2<TagBrowserActivity> {
/**
* Creates an {@link ActivityInstrumentationTestCase2} for the
* {@link TagBrowserActivity} activity.
*/
public TagsTest() {
super(TagBrowserActivity.class);
}
/**
* Verifies that the activity under test can be launched.
*/
public void testActivityTestCaseSetUpProperly() {
assertNotNull("activity should be launched successfully", getActivity());
}
}