summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRomain Guy <romainguy@android.com>2009-05-06 14:54:28 -0700
committerRomain Guy <romainguy@android.com>2009-05-06 16:49:56 -0700
commitd90a33111b3f1d0b2fff7ba9bafabc63fdb67d3a (patch)
tree6233ef66b9e5a7663b9db51f6d2a7052efb3bb74
parent413cf5f4536b9c029d07f99b1c769c026313cd12 (diff)
downloadframeworks_base-d90a33111b3f1d0b2fff7ba9bafabc63fdb67d3a.zip
frameworks_base-d90a33111b3f1d0b2fff7ba9bafabc63fdb67d3a.tar.gz
frameworks_base-d90a33111b3f1d0b2fff7ba9bafabc63fdb67d3a.tar.bz2
Add new setTag(int, Object) API to allow applications to specify several tags.
-rw-r--r--api/current.xml28
-rw-r--r--core/java/android/view/View.java106
-rw-r--r--tests/FrameworkTest/tests/src/com/android/frameworktest/view/SetTagsTest.java114
3 files changed, 247 insertions, 1 deletions
diff --git a/api/current.xml b/api/current.xml
index 509abe1..c222d42 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -135944,6 +135944,19 @@
visibility="public"
>
</method>
+<method name="getTag"
+ return="java.lang.Object"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="key" type="int">
+</parameter>
+</method>
<method name="getTop"
return="int"
abstract="false"
@@ -137843,6 +137856,21 @@
<parameter name="tag" type="java.lang.Object">
</parameter>
</method>
+<method name="setTag"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="key" type="int">
+</parameter>
+<parameter name="tag" type="java.lang.Object">
+</parameter>
+</method>
<method name="setTouchDelegate"
return="void"
abstract="false"
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 07c56ee..d042f28 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -61,6 +61,7 @@ import com.android.internal.view.menu.MenuBuilder;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.WeakHashMap;
import java.lang.ref.SoftReference;
import java.lang.reflect.Method;
import java.lang.reflect.InvocationTargetException;
@@ -1287,7 +1288,17 @@ public class View implements Drawable.Callback, KeyEvent.Callback {
* a Rect. :)
*/
static final ThreadLocal<Rect> sThreadLocal = new ThreadLocal<Rect>();
-
+
+ /**
+ * Map used to store views' tags.
+ */
+ private static WeakHashMap<View, SparseArray<Object>> sTags;
+
+ /**
+ * Lock used to access sTags.
+ */
+ private static final Object sTagsLock = new Object();
+
/**
* The animation currently associated with this view.
* @hide
@@ -7000,6 +7011,9 @@ public class View implements Drawable.Callback, KeyEvent.Callback {
* Returns this view's tag.
*
* @return the Object stored in this view as a tag
+ *
+ * @see #setTag(Object)
+ * @see #getTag(int)
*/
@ViewDebug.ExportedProperty
public Object getTag() {
@@ -7013,12 +7027,102 @@ public class View implements Drawable.Callback, KeyEvent.Callback {
* resorting to another data structure.
*
* @param tag an Object to tag the view with
+ *
+ * @see #getTag()
+ * @see #setTag(int, Object)
*/
public void setTag(final Object tag) {
mTag = tag;
}
/**
+ * Returns the tag associated with this view and the specified key.
+ *
+ * @param key The key identifying the tag
+ *
+ * @return the Object stored in this view as a tag
+ *
+ * @see #setTag(int, Object)
+ * @see #getTag()
+ */
+ public Object getTag(int key) {
+ SparseArray<Object> tags = null;
+ synchronized (sTagsLock) {
+ if (sTags != null) {
+ tags = sTags.get(this);
+ }
+ }
+
+ if (tags != null) return tags.get(key);
+ return null;
+ }
+
+ /**
+ * Sets a tag associated with this view and a key. A tag can be used
+ * to mark a view in its hierarchy and does not have to be unique within
+ * the hierarchy. Tags can also be used to store data within a view
+ * without resorting to another data structure.
+ *
+ * The specified key should be an id declared in the resources of the
+ * application to ensure it is unique. Keys identified as belonging to
+ * the Android framework or not associated with any package will cause
+ * an {@link IllegalArgumentException} to be thrown.
+ *
+ * @param key The key identifying the tag
+ * @param tag An Object to tag the view with
+ *
+ * @throws IllegalArgumentException If they specified key is not valid
+ *
+ * @see #setTag(Object)
+ * @see #getTag(int)
+ */
+ public void setTag(int key, final Object tag) {
+ // If the package id is 0x00 or 0x01, it's either an undefined package
+ // or a framework id
+ if ((key >>> 24) < 2) {
+ throw new IllegalArgumentException("The key must be an application-specific "
+ + "resource id.");
+ }
+
+ setTagInternal(this, key, tag);
+ }
+
+ /**
+ * Variation of {@link #setTag(int, Object)} that enforces the key to be a
+ * framework id.
+ *
+ * @hide
+ */
+ public void setTagInternal(int key, Object tag) {
+ if ((key >>> 24) != 0x1) {
+ throw new IllegalArgumentException("The key must be a framework-specific "
+ + "resource id.");
+ }
+
+ setTagInternal(this, key, tag);
+ }
+
+ private static void setTagInternal(View view, int key, Object tag) {
+ SparseArray<Object> tags = null;
+ synchronized (sTagsLock) {
+ if (sTags == null) {
+ sTags = new WeakHashMap<View, SparseArray<Object>>();
+ } else {
+ tags = sTags.get(view);
+ }
+ }
+
+ if (tags == null) {
+ tags = new SparseArray<Object>(2);
+ synchronized (sTagsLock) {
+ sTags.put(view, tags);
+ }
+ }
+
+ tags.put(key, tag);
+ }
+
+ /**
* Prints information about this view in the log output, with the tag
* {@link #VIEW_LOG_TAG}.
*
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/view/SetTagsTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/view/SetTagsTest.java
new file mode 100644
index 0000000..523eeaf
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/view/SetTagsTest.java
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2007 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.frameworktest.view;
+
+import com.android.frameworktest.R;
+import android.test.suitebuilder.annotation.MediumTest;
+
+import android.test.ActivityInstrumentationTestCase2;
+import android.widget.Button;
+
+/**
+ * Exercises {@link android.view.View}'s tags property.
+ */
+public class SetTagsTest extends ActivityInstrumentationTestCase2<Disabled> {
+ private Button mView;
+
+ public SetTagsTest() {
+ super("com.android.frameworktest", Disabled.class);
+ }
+
+ @Override
+ public void setUp() throws Exception {
+ super.setUp();
+
+ mView = (Button) getActivity().findViewById(R.id.disabledButton);
+ }
+
+ @MediumTest
+ public void testSetUpConditions() throws Exception {
+ assertNotNull(mView);
+ }
+
+ @MediumTest
+ public void testSetTag() throws Exception {
+ mView.setTag("1");
+ }
+
+ @MediumTest
+ public void testGetTag() throws Exception {
+ Object o = new Object();
+ mView.setTag(o);
+
+ final Object stored = mView.getTag();
+ assertNotNull(stored);
+ assertSame("The stored tag is inccorect", o, stored);
+ }
+
+ @MediumTest
+ public void testSetTagWithKey() throws Exception {
+ mView.setTag(R.id.a, "2");
+ }
+
+ @MediumTest
+ public void testGetTagWithKey() throws Exception {
+ Object o = new Object();
+ mView.setTag(R.id.a, o);
+
+ final Object stored = mView.getTag(R.id.a);
+ assertNotNull(stored);
+ assertSame("The stored tag is inccorect", o, stored);
+ }
+
+ @MediumTest
+ public void testSetTagWithFrameworkId() throws Exception {
+ boolean result = false;
+ try {
+ mView.setTag(android.R.id.list, "2");
+ } catch (IllegalArgumentException e) {
+ result = true;
+ }
+ assertTrue("Setting a tag with a framework id did not throw an exception", result);
+ }
+
+ @MediumTest
+ public void testSetTagWithNoPackageId() throws Exception {
+ boolean result = false;
+ try {
+ mView.setTag(0x000000AA, "2");
+ } catch (IllegalArgumentException e) {
+ result = true;
+ }
+ assertTrue("Setting a tag with an id with no package did not throw an exception", result);
+ }
+
+ @MediumTest
+ public void testSetTagInternalWithFrameworkId() throws Exception {
+ mView.setTagInternal(android.R.id.list, "2");
+ }
+
+ @MediumTest
+ public void testSetTagInternalWithApplicationId() throws Exception {
+ boolean result = false;
+ try {
+ mView.setTagInternal(R.id.a, "2");
+ } catch (IllegalArgumentException e) {
+ result = true;
+ }
+ assertTrue("Setting a tag with an id with app package did not throw an exception", result);
+ }
+}