Replace QuickContactBadge with custom widget
This commit is contained in:
parent
e70295efec
commit
923d91b012
9 changed files with 326 additions and 20 deletions
|
@ -17,11 +17,11 @@ import android.view.View.OnClickListener;
|
|||
import android.view.ViewGroup;
|
||||
import android.widget.BaseAdapter;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.QuickContactBadge;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.fsck.k9.R;
|
||||
import com.fsck.k9.activity.compose.RecipientAdapter;
|
||||
import com.fsck.k9.ui.ContactBadge;
|
||||
import com.fsck.k9.view.RecipientSelectView.Recipient;
|
||||
import com.fsck.k9.view.ThemeUtils;
|
||||
|
||||
|
@ -207,7 +207,7 @@ public class AlternateRecipientAdapter extends BaseAdapter {
|
|||
public final View layoutHeader, layoutItem;
|
||||
public final TextView headerName;
|
||||
public final TextView headerAddressLabel;
|
||||
public final QuickContactBadge headerPhoto;
|
||||
public final ContactBadge headerPhoto;
|
||||
public final View headerRemove;
|
||||
public final TextView itemAddress;
|
||||
public final TextView itemAddressLabel;
|
||||
|
@ -221,7 +221,7 @@ public class AlternateRecipientAdapter extends BaseAdapter {
|
|||
|
||||
headerName = (TextView) view.findViewById(R.id.alternate_header_name);
|
||||
headerAddressLabel = (TextView) view.findViewById(R.id.alternate_header_label);
|
||||
headerPhoto = (QuickContactBadge) view.findViewById(R.id.alternate_contact_photo);
|
||||
headerPhoto = (ContactBadge) view.findViewById(R.id.alternate_contact_photo);
|
||||
headerRemove = view.findViewById(R.id.alternate_remove);
|
||||
|
||||
itemAddress = (TextView) view.findViewById(R.id.alternate_address);
|
||||
|
|
|
@ -130,7 +130,7 @@ public class ContactPictureLoader {
|
|||
* Load a contact picture and display it using the supplied {@link ImageView} instance.
|
||||
*
|
||||
* <p>
|
||||
* If a picture is found in the cache, it is displayed in the {@code QuickContactBadge}
|
||||
* If a picture is found in the cache, it is displayed in the {@code ContactBadge}
|
||||
* immediately. Otherwise a {@link ContactPictureRetrievalTask} is started to try to load the
|
||||
* contact picture in a background thread. Depending on the result the contact picture or a
|
||||
* fallback picture is then stored in the bitmap cache.
|
||||
|
@ -140,7 +140,7 @@ public class ContactPictureLoader {
|
|||
* The {@link Address} instance holding the email address that is used to search the
|
||||
* contacts database.
|
||||
* @param imageView
|
||||
* The {@code QuickContactBadge} instance to receive the picture.
|
||||
* The {@code ContactBadge} instance to receive the picture.
|
||||
*
|
||||
* @see #mBitmapCache
|
||||
* @see #calculateFallbackBitmap(Address)
|
||||
|
@ -242,7 +242,7 @@ public class ContactPictureLoader {
|
|||
}
|
||||
}
|
||||
|
||||
// No task associated with the QuickContactBadge, or an existing task was cancelled
|
||||
// No task associated with the ContactBadge, or an existing task was cancelled
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -62,7 +62,6 @@ import android.widget.AdapterView.OnItemClickListener;
|
|||
import android.widget.CheckBox;
|
||||
import android.widget.CursorAdapter;
|
||||
import android.widget.ListView;
|
||||
import android.widget.QuickContactBadge;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
|
@ -114,6 +113,7 @@ import com.fsck.k9.search.SearchSpecification;
|
|||
import com.fsck.k9.search.SearchSpecification.SearchCondition;
|
||||
import com.fsck.k9.search.SearchSpecification.SearchField;
|
||||
import com.fsck.k9.search.SqlQueryBuilder;
|
||||
import com.fsck.k9.ui.ContactBadge;
|
||||
|
||||
|
||||
public class MessageListFragment extends Fragment implements OnItemClickListener,
|
||||
|
@ -1691,8 +1691,8 @@ public class MessageListFragment extends Fragment implements OnItemClickListener
|
|||
|
||||
}
|
||||
|
||||
QuickContactBadge contactBadge =
|
||||
(QuickContactBadge) view.findViewById(R.id.contact_badge);
|
||||
ContactBadge contactBadge =
|
||||
(ContactBadge) view.findViewById(R.id.contact_badge);
|
||||
if (mContactsPictureLoader != null) {
|
||||
holder.contactBadge = contactBadge;
|
||||
} else {
|
||||
|
@ -1802,7 +1802,7 @@ public class MessageListFragment extends Fragment implements OnItemClickListener
|
|||
Utility.setContactForBadge(holder.contactBadge, counterpartyAddress);
|
||||
/*
|
||||
* At least in Android 2.2 a different background + padding is used when no
|
||||
* email address is available. ListView reuses the views but QuickContactBadge
|
||||
* email address is available. ListView reuses the views but ContactBadge
|
||||
* doesn't reset the padding, so we do it ourselves.
|
||||
*/
|
||||
holder.contactBadge.setPadding(0, 0, 0, 0);
|
||||
|
@ -1960,7 +1960,7 @@ public class MessageListFragment extends Fragment implements OnItemClickListener
|
|||
public CheckBox flagged;
|
||||
public CheckBox selected;
|
||||
public int position = -1;
|
||||
public QuickContactBadge contactBadge;
|
||||
public ContactBadge contactBadge;
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
if (position != -1) {
|
||||
|
|
|
@ -14,10 +14,10 @@ import android.text.Editable;
|
|||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
import android.widget.EditText;
|
||||
import android.widget.QuickContactBadge;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.fsck.k9.K9;
|
||||
import com.fsck.k9.ui.ContactBadge;
|
||||
import com.fsck.k9.mail.Address;
|
||||
|
||||
import org.apache.james.mime4j.util.MimeUtil;
|
||||
|
@ -483,7 +483,7 @@ public class Utility {
|
|||
* @param contactBadge the badge to the set the contact for
|
||||
* @param address the address to look for a contact for.
|
||||
*/
|
||||
public static void setContactForBadge(QuickContactBadge contactBadge,
|
||||
public static void setContactForBadge(ContactBadge contactBadge,
|
||||
Address address) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
|
||||
Bundle extraContactInfo = new Bundle();
|
||||
|
|
306
k9mail/src/main/java/com/fsck/k9/ui/ContactBadge.java
Normal file
306
k9mail/src/main/java/com/fsck/k9/ui/ContactBadge.java
Normal file
|
@ -0,0 +1,306 @@
|
|||
package com.fsck.k9.ui;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.Bundle;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.accessibility.AccessibilityEvent;
|
||||
import android.view.accessibility.AccessibilityNodeInfo;
|
||||
import android.widget.ImageView;
|
||||
|
||||
import android.content.AsyncQueryHandler;
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Intent;
|
||||
import android.database.Cursor;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.net.Uri;
|
||||
import android.provider.ContactsContract.CommonDataKinds.Email;
|
||||
import android.provider.ContactsContract.Contacts;
|
||||
import android.provider.ContactsContract.Intents;
|
||||
import android.provider.ContactsContract.PhoneLookup;
|
||||
import android.provider.ContactsContract.QuickContact;
|
||||
import android.provider.ContactsContract.RawContacts;
|
||||
import android.view.View;
|
||||
import android.view.View.OnClickListener;
|
||||
|
||||
/**
|
||||
* ContactBadge replaces the android ContactBadge for custom drawing.
|
||||
*
|
||||
* Based on QuickContactBadge:
|
||||
* https://android.googlesource.com/platform/frameworks/base/+/master/core/java/android/widget/QuickContactBadge.java
|
||||
*/
|
||||
public class ContactBadge extends ImageView implements OnClickListener {
|
||||
|
||||
private Uri mContactUri;
|
||||
private String mContactEmail;
|
||||
private String mContactPhone;
|
||||
private QueryHandler mQueryHandler;
|
||||
private Bundle mExtras = null;
|
||||
|
||||
protected String[] mExcludeMimes = null;
|
||||
|
||||
static final private int TOKEN_EMAIL_LOOKUP = 0;
|
||||
static final private int TOKEN_PHONE_LOOKUP = 1;
|
||||
static final private int TOKEN_EMAIL_LOOKUP_AND_TRIGGER = 2;
|
||||
static final private int TOKEN_PHONE_LOOKUP_AND_TRIGGER = 3;
|
||||
|
||||
static final private String EXTRA_URI_CONTENT = "uri_content";
|
||||
|
||||
static final String[] EMAIL_LOOKUP_PROJECTION = new String[] {
|
||||
RawContacts.CONTACT_ID,
|
||||
Contacts.LOOKUP_KEY,
|
||||
};
|
||||
static final int EMAIL_ID_COLUMN_INDEX = 0;
|
||||
static final int EMAIL_LOOKUP_STRING_COLUMN_INDEX = 1;
|
||||
|
||||
static final String[] PHONE_LOOKUP_PROJECTION = new String[] {
|
||||
PhoneLookup._ID,
|
||||
PhoneLookup.LOOKUP_KEY,
|
||||
};
|
||||
static final int PHONE_ID_COLUMN_INDEX = 0;
|
||||
static final int PHONE_LOOKUP_STRING_COLUMN_INDEX = 1;
|
||||
|
||||
|
||||
public ContactBadge(Context context) {
|
||||
this(context, null);
|
||||
}
|
||||
public ContactBadge(Context context, AttributeSet attrs) {
|
||||
this(context, attrs, 0);
|
||||
}
|
||||
public ContactBadge(Context context, AttributeSet attrs, int defStyle) {
|
||||
super(context, attrs, defStyle);
|
||||
mQueryHandler = new QueryHandler(context.getContentResolver());
|
||||
setOnClickListener(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void drawableStateChanged() {
|
||||
super.drawableStateChanged();
|
||||
}
|
||||
|
||||
/** This call has no effect anymore, as there is only one QuickContact mode */
|
||||
@SuppressWarnings("unused")
|
||||
public void setMode(int size) {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDraw(Canvas canvas) {
|
||||
super.onDraw(canvas);
|
||||
}
|
||||
|
||||
/** True if a contact, an email address or a phone number has been assigned */
|
||||
private boolean isAssigned() {
|
||||
return mContactUri != null || mContactEmail != null || mContactPhone != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Assign the contact uri that this ContactBadge should be associated
|
||||
* with. Note that this is only used for displaying the QuickContact window and
|
||||
* won't bind the contact's photo for you. Call {@link #setImageDrawable(Drawable)} to set the
|
||||
* photo.
|
||||
*
|
||||
* @param contactUri Either a {@link Contacts#CONTENT_URI} or
|
||||
* {@link Contacts#CONTENT_LOOKUP_URI} style URI.
|
||||
*/
|
||||
public void assignContactUri(Uri contactUri) {
|
||||
mContactUri = contactUri;
|
||||
mContactEmail = null;
|
||||
mContactPhone = null;
|
||||
onContactUriChanged();
|
||||
}
|
||||
|
||||
/**
|
||||
* Assign a contact based on an email address. This should only be used when
|
||||
* the contact's URI is not available, as an extra query will have to be
|
||||
* performed to lookup the URI based on the email.
|
||||
*
|
||||
* @param emailAddress The email address of the contact.
|
||||
* @param lazyLookup If this is true, the lookup query will not be performed
|
||||
* until this view is clicked.
|
||||
*/
|
||||
public void assignContactFromEmail(String emailAddress, boolean lazyLookup) {
|
||||
assignContactFromEmail(emailAddress, lazyLookup, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Assign a contact based on an email address. This should only be used when
|
||||
* the contact's URI is not available, as an extra query will have to be
|
||||
* performed to lookup the URI based on the email.
|
||||
|
||||
@param emailAddress The email address of the contact.
|
||||
@param lazyLookup If this is true, the lookup query will not be performed
|
||||
until this view is clicked.
|
||||
@param extras A bundle of extras to populate the contact edit page with if the contact
|
||||
is not found and the user chooses to add the email address to an existing contact or
|
||||
create a new contact. Uses the same string constants as those found in
|
||||
{@link android.provider.ContactsContract.Intents.Insert}
|
||||
*/
|
||||
|
||||
public void assignContactFromEmail(String emailAddress, boolean lazyLookup, Bundle extras) {
|
||||
mContactEmail = emailAddress;
|
||||
mExtras = extras;
|
||||
if (!lazyLookup) {
|
||||
mQueryHandler.startQuery(TOKEN_EMAIL_LOOKUP, null,
|
||||
Uri.withAppendedPath(Email.CONTENT_LOOKUP_URI, Uri.encode(mContactEmail)),
|
||||
EMAIL_LOOKUP_PROJECTION, null, null, null);
|
||||
} else {
|
||||
mContactUri = null;
|
||||
onContactUriChanged();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Assign a contact based on a phone number. This should only be used when
|
||||
* the contact's URI is not available, as an extra query will have to be
|
||||
* performed to lookup the URI based on the phone number.
|
||||
*
|
||||
* @param phoneNumber The phone number of the contact.
|
||||
* @param lazyLookup If this is true, the lookup query will not be performed
|
||||
* until this view is clicked.
|
||||
*/
|
||||
|
||||
public void assignContactFromPhone(String phoneNumber, boolean lazyLookup) {
|
||||
assignContactFromPhone(phoneNumber, lazyLookup, new Bundle());
|
||||
}
|
||||
|
||||
/**
|
||||
* Assign a contact based on a phone number. This should only be used when
|
||||
* the contact's URI is not available, as an extra query will have to be
|
||||
* performed to lookup the URI based on the phone number.
|
||||
*
|
||||
* @param phoneNumber The phone number of the contact.
|
||||
* @param lazyLookup If this is true, the lookup query will not be performed
|
||||
* until this view is clicked.
|
||||
* @param extras A bundle of extras to populate the contact edit page with if the contact
|
||||
* is not found and the user chooses to add the phone number to an existing contact or
|
||||
* create a new contact. Uses the same string constants as those found in
|
||||
* {@link android.provider.ContactsContract.Intents.Insert}
|
||||
*/
|
||||
public void assignContactFromPhone(String phoneNumber, boolean lazyLookup, Bundle extras) {
|
||||
mContactPhone = phoneNumber;
|
||||
mExtras = extras;
|
||||
if (!lazyLookup) {
|
||||
mQueryHandler.startQuery(TOKEN_PHONE_LOOKUP, null,
|
||||
Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, mContactPhone),
|
||||
PHONE_LOOKUP_PROJECTION, null, null, null);
|
||||
} else {
|
||||
mContactUri = null;
|
||||
onContactUriChanged();
|
||||
}
|
||||
}
|
||||
|
||||
private void onContactUriChanged() {
|
||||
setEnabled(isAssigned());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
// If contact has been assigned, mExtras should no longer be null, but do a null check
|
||||
// anyway just in case assignContactFromPhone or Email was called with a null bundle or
|
||||
// wasn't assigned previously.
|
||||
final Bundle extras = (mExtras == null) ? new Bundle() : mExtras;
|
||||
if (mContactUri != null) {
|
||||
QuickContact.showQuickContact(getContext(), ContactBadge.this, mContactUri,
|
||||
QuickContact.MODE_LARGE, mExcludeMimes);
|
||||
} else if (mContactEmail != null) {
|
||||
extras.putString(EXTRA_URI_CONTENT, mContactEmail);
|
||||
mQueryHandler.startQuery(TOKEN_EMAIL_LOOKUP_AND_TRIGGER, extras,
|
||||
Uri.withAppendedPath(Email.CONTENT_LOOKUP_URI, Uri.encode(mContactEmail)),
|
||||
EMAIL_LOOKUP_PROJECTION, null, null, null);
|
||||
} else if (mContactPhone != null) {
|
||||
extras.putString(EXTRA_URI_CONTENT, mContactPhone);
|
||||
mQueryHandler.startQuery(TOKEN_PHONE_LOOKUP_AND_TRIGGER, extras,
|
||||
Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, mContactPhone),
|
||||
PHONE_LOOKUP_PROJECTION, null, null, null);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
|
||||
super.onInitializeAccessibilityEvent(event);
|
||||
event.setClassName(ContactBadge.class.getName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
|
||||
super.onInitializeAccessibilityNodeInfo(info);
|
||||
info.setClassName(ContactBadge.class.getName());
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a list of specific MIME-types to exclude and not display. For
|
||||
* example, this can be used to hide the {@link Contacts#CONTENT_ITEM_TYPE}
|
||||
* profile icon.
|
||||
*/
|
||||
public void setExcludeMimes(String[] excludeMimes) {
|
||||
mExcludeMimes = excludeMimes;
|
||||
}
|
||||
|
||||
private class QueryHandler extends AsyncQueryHandler {
|
||||
|
||||
public QueryHandler(ContentResolver cr) {
|
||||
super(cr);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onQueryComplete(int token, Object cookie, Cursor cursor) {
|
||||
Uri lookupUri = null;
|
||||
Uri createUri = null;
|
||||
boolean trigger = false;
|
||||
final Bundle extras = (cookie != null) ? (Bundle) cookie : new Bundle();
|
||||
try {
|
||||
switch(token) {
|
||||
case TOKEN_PHONE_LOOKUP_AND_TRIGGER:
|
||||
trigger = true;
|
||||
createUri = Uri.fromParts("tel", extras.getString(EXTRA_URI_CONTENT), null);
|
||||
|
||||
//$FALL-THROUGH$
|
||||
case TOKEN_PHONE_LOOKUP: {
|
||||
if (cursor != null && cursor.moveToFirst()) {
|
||||
long contactId = cursor.getLong(PHONE_ID_COLUMN_INDEX);
|
||||
String lookupKey = cursor.getString(PHONE_LOOKUP_STRING_COLUMN_INDEX);
|
||||
lookupUri = Contacts.getLookupUri(contactId, lookupKey);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case TOKEN_EMAIL_LOOKUP_AND_TRIGGER:
|
||||
trigger = true;
|
||||
createUri = Uri.fromParts("mailto",
|
||||
extras.getString(EXTRA_URI_CONTENT), null);
|
||||
|
||||
//$FALL-THROUGH$
|
||||
case TOKEN_EMAIL_LOOKUP: {
|
||||
if (cursor != null && cursor.moveToFirst()) {
|
||||
long contactId = cursor.getLong(EMAIL_ID_COLUMN_INDEX);
|
||||
String lookupKey = cursor.getString(EMAIL_LOOKUP_STRING_COLUMN_INDEX);
|
||||
lookupUri = Contacts.getLookupUri(contactId, lookupKey);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
if (cursor != null) {
|
||||
cursor.close();
|
||||
}
|
||||
}
|
||||
|
||||
mContactUri = lookupUri;
|
||||
onContactUriChanged();
|
||||
|
||||
if (trigger && lookupUri != null) {
|
||||
// Found contact, so trigger QuickContact
|
||||
QuickContact.showQuickContact(getContext(), ContactBadge.this, lookupUri,
|
||||
QuickContact.MODE_LARGE, ContactBadge.this.mExcludeMimes);
|
||||
} else if (createUri != null) {
|
||||
// Prompt user to add this person to contacts
|
||||
final Intent intent = new Intent(Intents.SHOW_OR_CREATE_CONTACT, createUri);
|
||||
extras.remove(EXTRA_URI_CONTENT);
|
||||
intent.putExtras(extras);
|
||||
getContext().startActivity(intent);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -23,7 +23,6 @@ import android.view.View.OnClickListener;
|
|||
import android.view.View.OnLongClickListener;
|
||||
import android.widget.CheckBox;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.QuickContactBadge;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
|
@ -43,6 +42,7 @@ import com.fsck.k9.mail.Message;
|
|||
import com.fsck.k9.mail.MessagingException;
|
||||
import com.fsck.k9.mail.internet.MimeUtility;
|
||||
import com.fsck.k9.ui.messageview.OnCryptoClickListener;
|
||||
import com.fsck.k9.ui.ContactBadge;
|
||||
|
||||
|
||||
public class MessageHeader extends LinearLayout implements OnClickListener, OnLongClickListener {
|
||||
|
@ -70,7 +70,7 @@ public class MessageHeader extends LinearLayout implements OnClickListener, OnLo
|
|||
|
||||
private MessageHelper mMessageHelper;
|
||||
private ContactPictureLoader mContactsPictureLoader;
|
||||
private QuickContactBadge mContactBadge;
|
||||
private ContactBadge mContactBadge;
|
||||
|
||||
private OnLayoutChangedListener mOnLayoutChangedListener;
|
||||
private OnCryptoClickListener onCryptoClickListener;
|
||||
|
@ -107,7 +107,7 @@ public class MessageHeader extends LinearLayout implements OnClickListener, OnLo
|
|||
mCcView = (TextView) findViewById(R.id.cc);
|
||||
mCcLabel = (TextView) findViewById(R.id.cc_label);
|
||||
|
||||
mContactBadge = (QuickContactBadge) findViewById(R.id.contact_badge);
|
||||
mContactBadge = (ContactBadge) findViewById(R.id.contact_badge);
|
||||
|
||||
mSubjectView = (TextView) findViewById(R.id.subject);
|
||||
mAdditionalHeadersView = (TextView) findViewById(R.id.additional_headers_view);
|
||||
|
|
|
@ -39,7 +39,7 @@
|
|||
|
||||
</LinearLayout>
|
||||
|
||||
<QuickContactBadge
|
||||
<com.fsck.k9.ui.ContactBadge
|
||||
android:id="@+id/contact_badge"
|
||||
android:layout_marginRight="8dip"
|
||||
android:layout_marginTop="4dip"
|
||||
|
|
|
@ -48,7 +48,7 @@
|
|||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical" >
|
||||
|
||||
<QuickContactBadge
|
||||
<com.fsck.k9.ui.ContactBadge
|
||||
android:id="@+id/contact_badge"
|
||||
android:layout_width="40dp"
|
||||
android:layout_height="40dp"
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
android:id="@+id/alternate_container_header"
|
||||
>
|
||||
|
||||
<QuickContactBadge
|
||||
<com.fsck.k9.ui.ContactBadge
|
||||
android:layout_width="42dp"
|
||||
android:layout_height="42dp"
|
||||
android:layout_marginLeft="12dp"
|
||||
|
@ -134,4 +134,4 @@
|
|||
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
|
|
Loading…
Reference in a new issue