--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<!-- placed inside act_edit as tabcontent -->
+<com.android.contacts.ui.widget.ReadOnlyContactEditorView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal"
+>
+
+ <!-- Left side color bar -->
+ <ImageView
+ android:id="@+id/color_bar"
+ android:layout_width="4dip"
+ android:layout_height="fill_parent"
+ />
+
+ <!-- The content -->
+ <LinearLayout
+ android:layout_width="0dip"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:orientation="vertical"
+ >
+
+ <!-- Account info header -->
+ <RelativeLayout android:id="@+id/header"
+ android:layout_height="64dip"
+ android:layout_width="fill_parent"
+ >
+
+ <ImageView android:id="@+id/header_color_bar"
+ android:layout_width="fill_parent"
+ android:layout_height="2dip"
+ android:layout_marginBottom="5dip"
+ />
+
+ <ImageView android:id="@+id/header_icon"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginLeft="7dip"
+ android:layout_marginRight="7dip"
+ android:layout_centerVertical="true"
+ android:layout_below="@id/header_color_bar"
+ />
+
+ <TextView android:id="@+id/header_account_type"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_toRightOf="@+id/header_icon"
+ android:layout_alignTop="@id/header_icon"
+ android:layout_marginTop="-4dip"
+
+ android:textSize="24sp"
+ android:textColor="?android:attr/textColorPrimary"
+ android:singleLine="true"
+ />
+
+ <TextView android:id="@+id/header_account_name"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_toRightOf="@+id/header_icon"
+ android:layout_alignBottom="@+id/header_icon"
+ android:layout_marginBottom="2dip"
+
+ android:textAppearance="?android:attr/textAppearanceSmall"
+ android:textColor="?android:attr/textColorPrimary"
+ android:singleLine="true"
+ />
+
+ <View
+ android:layout_width="fill_parent"
+ android:layout_height="1px"
+ android:layout_alignParentBottom="true"
+
+ android:background="?android:attr/listDivider"
+ />
+
+ </RelativeLayout>
+
+ <FrameLayout
+ android:id="@+id/stub_photo"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:paddingLeft="12dip"
+ android:paddingTop="10dip">
+
+ <include
+ android:id="@+id/edit_photo"
+ layout="@layout/item_photo_editor" />
+
+ </FrameLayout>
+
+ <TextView android:id="@+id/read_only_name"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="6dip"
+ android:layout_marginBottom="6dip"
+ android:layout_marginLeft="10dip"
+
+ android:textAppearance="?android:attr/textAppearanceLarge"
+ />
+
+ <View
+ android:layout_width="fill_parent"
+ android:layout_height="1px"
+ android:background="?android:attr/listDivider"
+ />
+
+ <TextView
+ android:id="@+id/read_only_warning"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="13dip"
+ android:layout_marginBottom="13dip"
+ android:layout_marginLeft="13dip"
+
+ android:textAppearance="?android:attr/textAppearanceSmall"
+ android:textColor="?android:attr/textColorPrimary"
+ android:drawableLeft="@android:drawable/ic_dialog_alert"
+ android:drawablePadding="10dip"
+ />
+
+ <View
+ android:layout_width="fill_parent"
+ android:layout_height="1px"
+ android:background="?android:attr/listDivider"
+ />
+
+ <LinearLayout android:id="@+id/sect_general"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ />
+ </LinearLayout>
+
+</com.android.contacts.ui.widget.ReadOnlyContactEditorView>
--- /dev/null
+<?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.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="fill_parent"
+ android:layout_height="?android:attr/listPreferredItemHeight"
+
+ android:orientation="vertical"
+>
+
+ <TextView android:id="@+id/label"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginLeft="10dip"
+ android:layout_marginTop="2dip"
+
+ android:textAppearance="?android:attr/textAppearanceLarge"
+ android:singleLine="true"
+ />
+
+ <TextView android:id="@+id/data"
+ android:layout_width="wrap_content"
+ android:layout_height="0px"
+ android:layout_weight="1"
+ android:layout_marginLeft="10dip"
+ android:layout_marginBottom="4dip"
+
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:singleLine="true"
+ />
+
+ <View
+ android:layout_width="fill_parent"
+ android:layout_height="1px"
+
+ android:background="?android:attr/listDivider"
+ />
+
+</LinearLayout>
\ No newline at end of file
import com.android.contacts.model.ContactsSource.EditType;
import com.android.contacts.model.Editor.EditorListener;
import com.android.contacts.model.EntityDelta.ValuesDelta;
-import com.android.contacts.ui.widget.ContactEditorView;
+import com.android.contacts.ui.widget.BaseContactEditorView;
import com.android.contacts.ui.widget.PhotoEditorView;
import com.android.contacts.util.EmptyService;
import com.android.contacts.util.WeakAsyncTask;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
-import java.util.List;
/**
* Activity for editing or inserting a contact.
ContactsSource.LEVEL_CONSTRAINTS);
final long rawContactId = values.getAsLong(RawContacts._ID);
- ContactEditorView editor = (ContactEditorView) inflater.inflate(
- R.layout.item_contact_editor, mContent, false);
+ BaseContactEditorView editor;
+ if (!source.readOnly) {
+ editor = (BaseContactEditorView) inflater.inflate(R.layout.item_contact_editor,
+ mContent, false);
+ } else {
+ editor = (BaseContactEditorView) inflater.inflate(
+ R.layout.item_read_only_contact_editor, mContent, false);
+ }
PhotoEditorView photoEditor = editor.getPhotoEditor();
photoEditor.setEditorListener(new PhotoListener(rawContactId, source.readOnly,
photoEditor));
int count = mContent.getChildCount();
for (int i = 0; i < count; i++) {
View childView = mContent.getChildAt(i);
- if (childView instanceof ContactEditorView) {
- ContactEditorView editor = (ContactEditorView) childView;
+ if (childView instanceof BaseContactEditorView) {
+ BaseContactEditorView editor = (BaseContactEditorView) childView;
PhotoEditorView photoEditor = editor.getPhotoEditor();
if (!photoEditor.equals(mEditor)) {
photoEditor.setSuperPrimary(false);
switch (requestCode) {
case PHOTO_PICKED_WITH_DATA: {
- ContactEditorView requestingEditor = null;
+ BaseContactEditorView requestingEditor = null;
for (int i = 0; i < mContent.getChildCount(); i++) {
View childView = mContent.getChildAt(i);
- if (childView instanceof ContactEditorView) {
- ContactEditorView editor = (ContactEditorView) childView;
+ if (childView instanceof BaseContactEditorView) {
+ BaseContactEditorView editor = (BaseContactEditorView) childView;
if (editor.getRawContactId() == mRawContactIdRequestingPhoto) {
requestingEditor = editor;
break;
--- /dev/null
+/*
+ * Copyright (C) 2009 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.ui.widget;
+
+import com.android.contacts.model.ContactsSource;
+import com.android.contacts.model.EntityDelta;
+import com.android.contacts.model.EntityModifier;
+import com.android.contacts.model.ContactsSource.EditType;
+import com.android.contacts.model.Editor.EditorListener;
+import com.android.contacts.model.EntityDelta.ValuesDelta;
+
+import android.content.Context;
+import android.content.Entity;
+import android.graphics.Bitmap;
+import android.provider.ContactsContract.Data;
+import android.provider.ContactsContract.RawContacts;
+import android.provider.ContactsContract.CommonDataKinds.Photo;
+import android.util.AttributeSet;
+import android.view.LayoutInflater;
+import android.widget.LinearLayout;
+
+/**
+ * Base view that provides common code for the editor interaction for a specific
+ * RawContact represented through an {@link EntityDelta}. Callers can
+ * reuse this view and quickly rebuild its contents through
+ * {@link #setState(EntityDelta, ContactsSource)}.
+ * <p>
+ * Internal updates are performed against {@link ValuesDelta} so that the
+ * source {@link Entity} can be swapped out. Any state-based changes, such as
+ * adding {@link Data} rows or changing {@link EditType}, are performed through
+ * {@link EntityModifier} to ensure that {@link ContactsSource} are enforced.
+ */
+public abstract class BaseContactEditorView extends LinearLayout {
+ protected LayoutInflater mInflater;
+
+ protected PhotoEditorView mPhoto;
+ protected boolean mHasPhotoEditor = false;
+
+ public BaseContactEditorView(Context context) {
+ super(context);
+ }
+
+ public BaseContactEditorView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ /**
+ * Assign the given {@link Bitmap} to the internal {@link PhotoEditorView}
+ * for the {@link EntityDelta} currently being edited.
+ */
+ public void setPhotoBitmap(Bitmap bitmap) {
+ mPhoto.setPhotoBitmap(bitmap);
+ }
+
+ /**
+ * Return true if the current {@link RawContacts} supports {@link Photo},
+ * which means that {@link PhotoEditorView} is enabled.
+ */
+ public boolean hasPhotoEditor() {
+ return mHasPhotoEditor;
+ }
+
+ /**
+ * Return true if internal {@link PhotoEditorView} has a {@link Photo} set.
+ */
+ public boolean hasSetPhoto() {
+ return mPhoto.hasSetPhoto();
+ }
+
+ public PhotoEditorView getPhotoEditor() {
+ return mPhoto;
+ }
+
+ /**
+ * @return the RawContact ID that this editor is editing.
+ */
+ public abstract long getRawContactId();
+
+ /**
+ * Set the internal state for this view, given a current
+ * {@link EntityDelta} state and the {@link ContactsSource} that
+ * apply to that state.
+ */
+ public abstract void setState(EntityDelta state, ContactsSource source);
+
+ /**
+ * Sets the {@link EditorListener} on the name field
+ */
+ public abstract void setNameEditorListener(EditorListener listener);
+}
import android.content.Context;
import android.content.Entity;
import android.content.res.Resources;
-import android.graphics.Bitmap;
import android.graphics.drawable.Drawable;
import android.provider.ContactsContract.Contacts;
import android.provider.ContactsContract.Data;
import android.view.ViewGroup;
import android.view.View.OnClickListener;
import android.widget.ImageView;
-import android.widget.LinearLayout;
import android.widget.TextView;
/**
* adding {@link Data} rows or changing {@link EditType}, are performed through
* {@link EntityModifier} to ensure that {@link ContactsSource} are enforced.
*/
-public class ContactEditorView extends LinearLayout implements OnClickListener {
- private LayoutInflater mInflater;
-
+public class ContactEditorView extends BaseContactEditorView implements OnClickListener {
private TextView mReadOnly;
private TextView mReadOnlyName;
- private PhotoEditorView mPhoto;
private View mPhotoStub;
private GenericEditorView mName;
- private boolean mHasPhotoEditor = false;
-
private ViewGroup mGeneral;
private ViewGroup mSecondary;
private boolean mSecondaryVisible;
this.setSecondaryVisible(false);
}
- /**
- * Assign the given {@link Bitmap} to the internal {@link PhotoEditorView}
- * for the {@link EntityDelta} currently being edited.
- */
- public void setPhotoBitmap(Bitmap bitmap) {
- mPhoto.setPhotoBitmap(bitmap);
- }
-
- /**
- * Return true if the current {@link RawContacts} supports {@link Photo},
- * which means that {@link PhotoEditorView} is enabled.
- */
- public boolean hasPhotoEditor() {
- return mHasPhotoEditor;
- }
-
- /**
- * Return true if internal {@link PhotoEditorView} has a {@link Photo} set.
- */
- public boolean hasSetPhoto() {
- return mPhoto.hasSetPhoto();
- }
-
- public PhotoEditorView getPhotoEditor() {
- return mPhoto;
- }
-
/** {@inheritDoc} */
public void onClick(View v) {
// Toggle visibility of secondary kinds
* {@link EntityDelta} state and the {@link ContactsSource} that
* apply to that state.
*/
+ @Override
public void setState(EntityDelta state, ContactsSource source) {
// Remove any existing sections
mGeneral.removeAllViews();
/**
* Sets the {@link EditorListener} on the name field
*/
+ @Override
public void setNameEditorListener(EditorListener listener) {
mName.setEditorListener(listener);
}
+ @Override
public long getRawContactId() {
return mRawContactId;
}
--- /dev/null
+/*
+ * Copyright (C) 2009 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.ui.widget;
+
+import com.android.contacts.R;
+import com.android.contacts.model.ContactsSource;
+import com.android.contacts.model.EntityDelta;
+import com.android.contacts.model.EntityModifier;
+import com.android.contacts.model.ContactsSource.DataKind;
+import com.android.contacts.model.ContactsSource.EditType;
+import com.android.contacts.model.Editor.EditorListener;
+import com.android.contacts.model.EntityDelta.ValuesDelta;
+
+import android.content.Context;
+import android.content.Entity;
+import android.provider.ContactsContract.Contacts;
+import android.provider.ContactsContract.Data;
+import android.provider.ContactsContract.RawContacts;
+import android.provider.ContactsContract.CommonDataKinds.Email;
+import android.provider.ContactsContract.CommonDataKinds.Phone;
+import android.provider.ContactsContract.CommonDataKinds.Photo;
+import android.provider.ContactsContract.CommonDataKinds.StructuredName;
+import android.telephony.PhoneNumberUtils;
+import android.text.TextUtils;
+import android.util.AttributeSet;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+import java.util.ArrayList;
+
+/**
+ * Custom view that displays read-only contacts in the edit screen.
+ */
+class ReadOnlyContactEditorView extends BaseContactEditorView {
+
+ private View mPhotoStub;
+ private TextView mName;
+ private TextView mReadOnlyWarning;
+ private ViewGroup mGeneral;
+
+ private View mHeaderColorBar;
+ private View mSideBar;
+ private ImageView mHeaderIcon;
+ private TextView mHeaderAccountType;
+ private TextView mHeaderAccountName;
+
+ private long mRawContactId = -1;
+
+ public ReadOnlyContactEditorView(Context context) {
+ super(context);
+ }
+
+ public ReadOnlyContactEditorView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ protected void onFinishInflate() {
+ super.onFinishInflate();
+
+ mInflater = (LayoutInflater)getContext().getSystemService(
+ Context.LAYOUT_INFLATER_SERVICE);
+
+ mPhoto = (PhotoEditorView)findViewById(R.id.edit_photo);
+ mPhotoStub = findViewById(R.id.stub_photo);
+
+ mName = (TextView) findViewById(R.id.read_only_name);
+ mReadOnlyWarning = (TextView) findViewById(R.id.read_only_warning);
+ mGeneral = (ViewGroup)findViewById(R.id.sect_general);
+
+ mHeaderColorBar = findViewById(R.id.header_color_bar);
+ mSideBar = findViewById(R.id.color_bar);
+ mHeaderIcon = (ImageView) findViewById(R.id.header_icon);
+ mHeaderAccountType = (TextView) findViewById(R.id.header_account_type);
+ mHeaderAccountName = (TextView) findViewById(R.id.header_account_name);
+ }
+
+ /**
+ * Set the internal state for this view, given a current
+ * {@link EntityDelta} state and the {@link ContactsSource} that
+ * apply to that state.
+ *
+ * TODO: make this more generic using data from the source
+ */
+ @Override
+ public void setState(EntityDelta state, ContactsSource source) {
+ // Remove any existing sections
+ mGeneral.removeAllViews();
+
+ // Bail if invalid state or source
+ if (state == null || source == null) return;
+
+ // Make sure we have StructuredName
+ EntityModifier.ensureKindExists(state, source, StructuredName.CONTENT_ITEM_TYPE);
+
+ // Fill in the header info
+ mHeaderColorBar.setBackgroundColor(source.getHeaderColor(mContext));
+ mSideBar.setBackgroundColor(source.getSideBarColor(mContext));
+ ValuesDelta values = state.getValues();
+ String accountName = values.getAsString(RawContacts.ACCOUNT_NAME);
+ CharSequence accountType = source.getDisplayLabel(mContext);
+ if (TextUtils.isEmpty(accountType)) {
+ accountType = mContext.getString(R.string.account_phone);
+ }
+ if (!TextUtils.isEmpty(accountName)) {
+ mHeaderAccountName.setText(
+ mContext.getString(R.string.from_account_format, accountName));
+ }
+ mHeaderAccountType.setText(mContext.getString(R.string.account_type_format, accountType));
+ mHeaderIcon.setImageDrawable(source.getDisplayIcon(mContext));
+
+ mRawContactId = values.getAsLong(RawContacts._ID);
+
+ ValuesDelta primary;
+
+ // Photo
+ DataKind kind = source.getKindForMimetype(Photo.CONTENT_ITEM_TYPE);
+ if (kind != null) {
+ EntityModifier.ensureKindExists(state, source, Photo.CONTENT_ITEM_TYPE);
+ mHasPhotoEditor = (source.getKindForMimetype(Photo.CONTENT_ITEM_TYPE) != null);
+ primary = state.getPrimaryEntry(Photo.CONTENT_ITEM_TYPE);
+ mPhoto.setValues(kind, primary, state, source.readOnly);
+ if (!mHasPhotoEditor || !mPhoto.hasSetPhoto()) {
+ mPhotoStub.setVisibility(View.GONE);
+ } else {
+ mPhotoStub.setVisibility(View.VISIBLE);
+ }
+ } else {
+ mPhotoStub.setVisibility(View.VISIBLE);
+ }
+
+ // Name
+ primary = state.getPrimaryEntry(StructuredName.CONTENT_ITEM_TYPE);
+ mName.setText(primary.getAsString(StructuredName.DISPLAY_NAME));
+
+ // Read only warning
+ mReadOnlyWarning.setText(mContext.getString(R.string.contact_read_only, accountType));
+
+ // Phones
+ ArrayList<ValuesDelta> phones = state.getMimeEntries(Phone.CONTENT_ITEM_TYPE);
+ if (phones != null) {
+ for (ValuesDelta phone : phones) {
+ View field = mInflater.inflate(
+ R.layout.item_read_only_field, mGeneral, false);
+ TextView v;
+ v = (TextView) field.findViewById(R.id.label);
+ v.setText(mContext.getText(R.string.phoneLabelsGroup));
+ v = (TextView) field.findViewById(R.id.data);
+ v.setText(PhoneNumberUtils.formatNumber(phone.getAsString(Phone.NUMBER)));
+ mGeneral.addView(field);
+ }
+ }
+
+ // Emails
+ ArrayList<ValuesDelta> emails = state.getMimeEntries(Email.CONTENT_ITEM_TYPE);
+ if (emails != null) {
+ for (ValuesDelta email : emails) {
+ View field = mInflater.inflate(
+ R.layout.item_read_only_field, mGeneral, false);
+ TextView v;
+ v = (TextView) field.findViewById(R.id.label);
+ v.setText(mContext.getText(R.string.emailLabelsGroup));
+ v = (TextView) field.findViewById(R.id.data);
+ v.setText(email.getAsString(Email.DATA));
+ mGeneral.addView(field);
+ }
+ }
+
+ // Hide mGeneral if it's empty
+ if (mGeneral.getChildCount() > 0) {
+ mGeneral.setVisibility(View.VISIBLE);
+ } else {
+ mGeneral.setVisibility(View.GONE);
+ }
+ }
+
+ /**
+ * Sets the {@link EditorListener} on the name field
+ */
+ @Override
+ public void setNameEditorListener(EditorListener listener) {
+ // do nothing
+ }
+
+ @Override
+ public long getRawContactId() {
+ return mRawContactId;
+ }
+}