Small clean-up of stream items utility class.
We do not need a way to add a set of stream items to a container: we now
use a ListView.
Do not set the listener in the helper method: we can just do that in the
adapter itself.
Bug: 5119353
Change-Id: Id647ddc358f82b5fee8628b06645412e48712229
diff --git a/src/com/android/contacts/detail/ContactDetailDisplayUtils.java b/src/com/android/contacts/detail/ContactDetailDisplayUtils.java
index e88e5e8..0c59695 100644
--- a/src/com/android/contacts/detail/ContactDetailDisplayUtils.java
+++ b/src/com/android/contacts/detail/ContactDetailDisplayUtils.java
@@ -249,36 +249,15 @@
}
}
- /**
- * Displays the social stream items under the given layout.
- */
- public static void showSocialStreamItems(LayoutInflater inflater, Context context,
- Result contactData, LinearLayout streamContainer, View.OnClickListener listener) {
- if (streamContainer != null) {
- streamContainer.removeAllViews();
- List<StreamItemEntry> streamItems = contactData.getStreamItems();
- for (StreamItemEntry streamItem : streamItems) {
- addStreamItemToContainer(inflater, context, streamItem, streamContainer, listener);
- }
- }
- }
-
- public static View addStreamItemToContainer(LayoutInflater inflater, Context context,
- StreamItemEntry streamItem, LinearLayout streamContainer,
- View.OnClickListener listener) {
+ /** Creates the view that represents a stream item. */
+ public static View createStreamItemView(LayoutInflater inflater, Context context,
+ StreamItemEntry streamItem, LinearLayout parent) {
View oneColumnView = inflater.inflate(R.layout.stream_item_one_column,
- streamContainer, false);
+ parent, false);
ViewGroup contentBox = (ViewGroup) oneColumnView.findViewById(R.id.stream_item_content);
int internalPadding = context.getResources().getDimensionPixelSize(
R.dimen.detail_update_section_internal_padding);
- // Add the listener only if there is an action and corresponding URI.
- if (streamItem.getAction() != null && streamItem.getActionUri() != null) {
- contentBox.setTag(streamItem);
- contentBox.setOnClickListener(listener);
- contentBox.setFocusable(true);
- }
-
// TODO: This is not the correct layout for a stream item with photos. Photos should be
// displayed first, then the update text either to the right of the final image (if there
// are an odd number of images) or below the last row of images (if there are an even
@@ -335,8 +314,8 @@
}
}
- if (streamContainer != null) {
- streamContainer.addView(oneColumnView);
+ if (parent != null) {
+ parent.addView(oneColumnView);
}
return oneColumnView;
@@ -358,7 +337,9 @@
} else {
commentsView.setVisibility(View.GONE);
}
- parent.addView(textUpdate);
+ if (parent != null) {
+ parent.addView(textUpdate);
+ }
return textUpdate;
}
diff --git a/src/com/android/contacts/detail/ContactDetailUpdatesFragment.java b/src/com/android/contacts/detail/ContactDetailUpdatesFragment.java
index 308254f..bb2bdb4 100644
--- a/src/com/android/contacts/detail/ContactDetailUpdatesFragment.java
+++ b/src/com/android/contacts/detail/ContactDetailUpdatesFragment.java
@@ -66,16 +66,31 @@
@Override
public void onClick(View view) {
StreamItemEntry streamItemEntry = (StreamItemEntry) view.getTag();
- Uri uri;
- try {
- uri = Uri.parse(streamItemEntry.getActionUri());
- } catch (Throwable throwable) {
- Log.e(TAG, "invalid URI for stream item #" + streamItemEntry.getId() + ": "
- + streamItemEntry.getActionUri());
+ if (streamItemEntry == null) {
+ // Ignore if this item does not have a stream item associated with it.
return;
}
- Intent streamItemIntent = new Intent(streamItemEntry.getAction(), uri);
- startActivity(streamItemIntent);
+ String actionUri = streamItemEntry.getActionUri();
+ if (actionUri == null) {
+ // Ignore if this item does not have a URI.
+ return;
+ }
+ // Parse the URI.
+ Uri uri;
+ try {
+ uri = Uri.parse(actionUri);
+ } catch (Throwable throwable) {
+ // This may fail if the URI is invalid: instead of failing, just ignore it.
+ Log.e(TAG, "invalid URI for stream item #" + streamItemEntry.getId() + ": "
+ + actionUri);
+ return;
+ }
+ String action = streamItemEntry.getAction();
+ if (action == null) {
+ // Ignore if this item does not have an action.
+ return;
+ }
+ startActivity(new Intent(action, uri));
}
};
diff --git a/src/com/android/contacts/detail/StreamItemAdapter.java b/src/com/android/contacts/detail/StreamItemAdapter.java
index d8f4a81..95880d7 100644
--- a/src/com/android/contacts/detail/StreamItemAdapter.java
+++ b/src/com/android/contacts/detail/StreamItemAdapter.java
@@ -74,8 +74,19 @@
if (position == 0) {
return mInflater.inflate(R.layout.updates_header_contact, null);
}
- return ContactDetailDisplayUtils.addStreamItemToContainer(
- mInflater, mContext, (StreamItemEntry) getItem(position), null, mListener);
+ StreamItemEntry streamItem = (StreamItemEntry) getItem(position);
+ View view = ContactDetailDisplayUtils.createStreamItemView(
+ mInflater, mContext, streamItem, null);
+ if (streamItem.getAction() != null && streamItem.getActionUri() != null) {
+ view.setTag(streamItem);
+ view.setFocusable(true);
+ view.setOnClickListener(mListener);
+ } else {
+ view.setTag(null);
+ view.setFocusable(false);
+ view.setOnClickListener(null);
+ }
+ return view;
}
@Override
diff --git a/tests/src/com/android/contacts/detail/ContactDetailDisplayUtilsTest.java b/tests/src/com/android/contacts/detail/ContactDetailDisplayUtilsTest.java
index 98001ae..aebb8c2 100644
--- a/tests/src/com/android/contacts/detail/ContactDetailDisplayUtilsTest.java
+++ b/tests/src/com/android/contacts/detail/ContactDetailDisplayUtilsTest.java
@@ -18,6 +18,7 @@
import com.android.contacts.R;
import com.android.contacts.util.StreamItemEntry;
+import com.android.contacts.util.StreamItemEntryBuilder;
import android.content.Context;
import android.test.AndroidTestCase;
@@ -27,7 +28,6 @@
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
-import android.widget.LinearLayout;
import android.widget.TextView;
/**
@@ -37,14 +37,11 @@
public class ContactDetailDisplayUtilsTest extends AndroidTestCase {
private static final String TEST_STREAM_ITEM_TEXT = "text";
- private LinearLayout mParent;
private LayoutInflater mLayoutInflater;
- private FakeOnClickListener mListener = new FakeOnClickListener();
@Override
protected void setUp() throws Exception {
super.setUp();
- mParent = new LinearLayout(getContext());
mLayoutInflater =
(LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
@@ -72,81 +69,6 @@
assertGone(streamItemView, R.id.stream_item_comments);
}
- public void testAddStreamItemToContainer_NoAction() {
- StreamItemEntry streamItem = getTestBuilder()
- .setAction(null)
- .setActionUri(null)
- .build();
- addStreamItemToContainer(streamItem, mListener);
- assertStreamItemNotClickable();
- }
-
- public void testAddStreamItemToContainer_WithActionButNoActionUri() {
- StreamItemEntry streamItem = getTestBuilder()
- .setAction("action")
- .setActionUri(null)
- .build();
- addStreamItemToContainer(streamItem, mListener);
- assertStreamItemNotClickable();
- }
-
- public void testAddStreamItemToContainer_WithActionUriButNoAction() {
- StreamItemEntry streamItem = getTestBuilder()
- .setAction(null)
- .setActionUri("http://www.google.com")
- .build();
- addStreamItemToContainer(streamItem, mListener);
- assertStreamItemNotClickable();
- }
-
- public void testAddStreamItemToContainer_WithActionAndActionUri() {
- StreamItemEntry streamItem = getTestBuilder()
- .setAction("action")
- .setActionUri("http://www.google.com")
- .build();
- addStreamItemToContainer(streamItem, mListener);
- assertStreamItemClickable();
- assertStreamItemHasOnClickListener();
- assertStreamItemHasTag(streamItem);
- }
-
- /** Checks that the stream item view is clickable. */
- private void assertStreamItemClickable() {
- View streamItemView = mParent.findViewById(R.id.stream_item_content);
- assertNotNull("should have a stream item", streamItemView);
- assertTrue("should be clickable", streamItemView.isClickable());
- assertTrue("should be focusable", streamItemView.isFocusable());
- }
-
- /** Asserts that there is a stream item but it is not clickable. */
- private void assertStreamItemNotClickable() {
- View streamItemView = mParent.findViewById(R.id.stream_item_content);
- assertNotNull("should have a stream item", streamItemView);
- assertFalse("should not be clickable", streamItemView.isClickable());
- assertFalse("should not be focusable", streamItemView.isFocusable());
- }
-
- /** Checks that the stream item view has a click listener. */
- private void assertStreamItemHasOnClickListener() {
- // Check that the on-click listener is invoked when clicked.
- View streamItemView = mParent.findViewById(R.id.stream_item_content);
- assertFalse("listener should have not been invoked yet", mListener.clicked);
- streamItemView.performClick();
- assertTrue("listener should have been invoked", mListener.clicked);
- }
-
- /** Checks that the stream item view has the given stream item as its tag. */
- private void assertStreamItemHasTag(StreamItemEntry streamItem) {
- // The view's tag should point to the stream item entry for this view.
- View streamItemView = mParent.findViewById(R.id.stream_item_content);
- Object tag = streamItemView.getTag();
- assertNotNull("should have a tag", tag);
- assertTrue("should be a StreamItemEntry", tag instanceof StreamItemEntry);
- StreamItemEntry streamItemTag = (StreamItemEntry) tag;
- // The streamItem itself should be in the tag.
- assertSame(streamItem, streamItemTag);
- }
-
/** Checks that the given id corresponds to a visible text view with the expected text. */
private void assertHasText(View parent, int textViewId, String expectedText) {
TextView textView = (TextView) parent.findViewById(textViewId);
@@ -187,70 +109,7 @@
*/
private View addStreamItemText(StreamItemEntry streamItem) {
return ContactDetailDisplayUtils.addStreamItemText(
- mLayoutInflater, getContext(), streamItem, mParent);
- }
-
- /**
- * Calls {@link ContactDetailDisplayUtils#addStreamItemToContainer(LayoutInflater,
- * Context,StreamItemEntry, LinearLayout, android.view.View.OnClickListener)} with the default
- * parameters and the given stream item and listener.
- */
- private void addStreamItemToContainer(StreamItemEntry streamItem,
- View.OnClickListener listener) {
- ContactDetailDisplayUtils.addStreamItemToContainer(mLayoutInflater, getContext(),
- streamItem, mParent, listener);
- }
-
- /**
- * Simple fake implementation of {@link View.OnClickListener} which sets a member variable to
- * true when clicked.
- */
- private final class FakeOnClickListener implements View.OnClickListener {
- public boolean clicked = false;
-
- @Override
- public void onClick(View view) {
- clicked = true;
- }
- }
-
- private static class StreamItemEntryBuilder {
- private long mId;
- private String mText;
- private String mComment;
- private long mTimestamp;
- private String mAction;
- private String mActionUri;
- private String mResPackage;
- private int mIconRes;
- private int mLabelRes;
-
- public StreamItemEntryBuilder() {}
-
- public StreamItemEntryBuilder setText(String text) {
- mText = text;
- return this;
- }
-
- public StreamItemEntryBuilder setComment(String comment) {
- mComment = comment;
- return this;
- }
-
- public StreamItemEntryBuilder setAction(String action) {
- mAction = action;
- return this;
- }
-
- public StreamItemEntryBuilder setActionUri(String actionUri) {
- mActionUri = actionUri;
- return this;
- }
-
- public StreamItemEntry build() {
- return new StreamItemEntry(mId, mText, mComment, mTimestamp, mAction, mActionUri,
- mResPackage, mIconRes, mLabelRes);
- }
+ mLayoutInflater, getContext(), streamItem, null);
}
private StreamItemEntryBuilder getTestBuilder() {
diff --git a/tests/src/com/android/contacts/detail/StreamItemAdapterTest.java b/tests/src/com/android/contacts/detail/StreamItemAdapterTest.java
new file mode 100644
index 0000000..99ae834
--- /dev/null
+++ b/tests/src/com/android/contacts/detail/StreamItemAdapterTest.java
@@ -0,0 +1,173 @@
+/*
+ * Copyright (C) 2011 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.contacts.detail;
+
+import com.android.contacts.util.StreamItemEntry;
+import com.android.contacts.util.StreamItemEntryBuilder;
+import com.google.common.collect.Lists;
+
+import android.content.Intent;
+import android.test.AndroidTestCase;
+import android.view.View;
+
+import java.util.ArrayList;
+
+/**
+ * Unit tests for {@link StreamItemAdapter}.
+ */
+public class StreamItemAdapterTest extends AndroidTestCase {
+ private StreamItemAdapter mAdapter;
+ private FakeOnClickListener mListener;
+ private View mView;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ mListener = new FakeOnClickListener();
+ mAdapter = new StreamItemAdapter(getContext(), mListener);
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ mAdapter = null;
+ mListener = null;
+ super.tearDown();
+ }
+
+ public void testGetCount_Empty() {
+ mAdapter.setStreamItems(createStreamItemList(0));
+ // There is actually one view: the header.
+ assertEquals(1, mAdapter.getCount());
+ }
+
+ public void testGetCount_NonEmpty() {
+ mAdapter.setStreamItems(createStreamItemList(3));
+ // There is one extra view: the header.
+ assertEquals(4, mAdapter.getCount());
+ }
+
+ public void testGetView_WithAction() {
+ StreamItemEntry streamItem = createStreamItemWithAction();
+ mAdapter.setStreamItems(Lists.newArrayList(streamItem));
+ mView = mAdapter.getView(1, null, null);
+ assertStreamItemViewHasTag(streamItem);
+ assertStreamItemViewHasOnClickListener();
+ assertStreamItemViewFocusable();
+ }
+
+ public void testGetView_WithoutAction() {
+ mAdapter.setStreamItems(Lists.newArrayList(createStreamItemWithoutAction()));
+ mView = mAdapter.getView(1, null, null);
+ assertStreamItemViewHasNoTag();
+ assertStreamItemViewHasNoOnClickListener();
+ assertStreamItemViewNotFocusable();
+ }
+
+ public void testGetView_Header() {
+ // Just check that we can inflate it correctly.
+ mView = mAdapter.getView(0, null, null);
+ }
+
+ /** Counter used by {@link #createStreamItemEntryBuilder()} to create unique builders. */
+ private int mCreateStreamItemEntryBuilderCounter = 0;
+
+ /** Returns a stream item builder with basic information in it. */
+ private StreamItemEntryBuilder createStreamItemEntryBuilder() {
+ return new StreamItemEntryBuilder().setText(
+ "text #" + mCreateStreamItemEntryBuilderCounter++);
+ }
+
+ /** Returns a stream item with an action and action URI set. */
+ private StreamItemEntry createStreamItemWithAction() {
+ return createStreamItemEntryBuilder()
+ .setAction(Intent.ACTION_VIEW)
+ .setActionUri("http://www.google.com")
+ .build();
+ }
+
+ /** Returns a stream item without an action and action URI set. */
+ private StreamItemEntry createStreamItemWithoutAction() {
+ return createStreamItemEntryBuilder()
+ .setAction(null)
+ .setActionUri(null)
+ .build();
+ }
+
+ /** Creates a list containing the given number of {@link StreamItemEntry}s. */
+ private ArrayList<StreamItemEntry> createStreamItemList(int count) {
+ ArrayList<StreamItemEntry> list = Lists.newArrayList();
+ for (int index = 0; index < count; ++index) {
+ list.add(createStreamItemEntryBuilder().build());
+ }
+ return list;
+ }
+
+ /** Checks that the stream item view has a click listener. */
+ private void assertStreamItemViewHasOnClickListener() {
+ assertFalse("listener should have not been invoked yet", mListener.clicked);
+ mView.performClick();
+ assertTrue("listener should have been invoked", mListener.clicked);
+ }
+
+ /** Checks that the stream item view does not have a click listener. */
+ private void assertStreamItemViewHasNoOnClickListener() {
+ assertFalse("listener should have not been invoked yet", mListener.clicked);
+ mView.performClick();
+ assertFalse("listener should have not been invoked", mListener.clicked);
+ }
+
+ /** Checks that the stream item view is clickable. */
+ private void assertStreamItemViewFocusable() {
+ assertNotNull("should have a stream item", mView);
+ assertTrue("should be focusable", mView.isFocusable());
+ }
+
+ /** Asserts that there is a stream item but it is not clickable. */
+ private void assertStreamItemViewNotFocusable() {
+ assertNotNull("should have a stream item", mView);
+ assertFalse("should not be focusable", mView.isFocusable());
+ }
+
+ /** Checks that the stream item view has the given stream item as its tag. */
+ private void assertStreamItemViewHasTag(StreamItemEntry streamItem) {
+ Object tag = mView.getTag();
+ assertNotNull("should have a tag", tag);
+ assertTrue("should be a StreamItemEntry", tag instanceof StreamItemEntry);
+ StreamItemEntry streamItemTag = (StreamItemEntry) tag;
+ // The streamItem itself should be in the tag.
+ assertSame(streamItem, streamItemTag);
+ }
+
+ /** Checks that the stream item view has the given stream item as its tag. */
+ private void assertStreamItemViewHasNoTag() {
+ Object tag = mView.getTag();
+ assertNull("should not have a tag", tag);
+ }
+
+ /**
+ * Simple fake implementation of {@link View.OnClickListener} which sets a member variable to
+ * true when clicked.
+ */
+ private final class FakeOnClickListener implements View.OnClickListener {
+ public boolean clicked = false;
+
+ @Override
+ public void onClick(View view) {
+ clicked = true;
+ }
+ }
+}
diff --git a/tests/src/com/android/contacts/util/StreamItemEntryBuilder.java b/tests/src/com/android/contacts/util/StreamItemEntryBuilder.java
new file mode 100644
index 0000000..8a17b4a
--- /dev/null
+++ b/tests/src/com/android/contacts/util/StreamItemEntryBuilder.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2011 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.contacts.util;
+
+/**
+ * Builder for {@link StreamItemEntry}s to make writing tests easier.
+ */
+public class StreamItemEntryBuilder {
+ private long mId;
+ private String mText;
+ private String mComment;
+ private long mTimestamp;
+ private String mAction;
+ private String mActionUri;
+ private String mResPackage;
+ private int mIconRes;
+ private int mLabelRes;
+
+ public StreamItemEntryBuilder() {}
+
+ public StreamItemEntryBuilder setText(String text) {
+ mText = text;
+ return this;
+ }
+
+ public StreamItemEntryBuilder setComment(String comment) {
+ mComment = comment;
+ return this;
+ }
+
+ public StreamItemEntryBuilder setAction(String action) {
+ mAction = action;
+ return this;
+ }
+
+ public StreamItemEntryBuilder setActionUri(String actionUri) {
+ mActionUri = actionUri;
+ return this;
+ }
+
+ public StreamItemEntry build() {
+ return new StreamItemEntry(mId, mText, mComment, mTimestamp, mAction, mActionUri,
+ mResPackage, mIconRes, mLabelRes);
+ }
+}
\ No newline at end of file