mirror of
https://github.com/moparisthebest/open-keychain
synced 2024-11-27 19:22:14 -05:00
certs: provider cleanup and bugfixing
This commit is contained in:
parent
6bacb5ff51
commit
5c28da44d6
@ -451,6 +451,9 @@ public class KeychainProvider extends ContentProvider {
|
|||||||
projectionMap.put(KeyRingsColumns.MASTER_KEY_ID, Tables.KEY_RINGS + "."
|
projectionMap.put(KeyRingsColumns.MASTER_KEY_ID, Tables.KEY_RINGS + "."
|
||||||
+ KeyRingsColumns.MASTER_KEY_ID);
|
+ KeyRingsColumns.MASTER_KEY_ID);
|
||||||
|
|
||||||
|
// this is the count of known secret keys who certified this uid
|
||||||
|
projectionMap.put("verified", "COUNT(" + Tables.KEYS + "." + Keys._ID + ") AS verified");
|
||||||
|
|
||||||
return projectionMap;
|
return projectionMap;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -659,38 +662,37 @@ public class KeychainProvider extends ContentProvider {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case PUBLIC_KEY_RING_BY_MASTER_KEY_ID_USER_ID:
|
case PUBLIC_KEY_RING_BY_MASTER_KEY_ID_USER_ID:
|
||||||
qb.setTables(Tables.USER_IDS + " INNER JOIN " + Tables.KEY_RINGS + " ON " + "("
|
|
||||||
+ Tables.KEY_RINGS + "." + BaseColumns._ID + " = " + Tables.USER_IDS + "."
|
|
||||||
+ KeysColumns.KEY_RING_ROW_ID + " )");
|
|
||||||
qb.appendWhere(Tables.KEY_RINGS + "." + KeyRingsColumns.MASTER_KEY_ID + " = ");
|
|
||||||
qb.appendWhereEscapeString(uri.getPathSegments().get(3));
|
|
||||||
|
|
||||||
qb.setProjectionMap(getProjectionMapForUserIds());
|
|
||||||
|
|
||||||
break;
|
|
||||||
|
|
||||||
case PUBLIC_KEY_RING_USER_ID:
|
case PUBLIC_KEY_RING_USER_ID:
|
||||||
case SECRET_KEY_RING_USER_ID:
|
case SECRET_KEY_RING_USER_ID:
|
||||||
qb.setTables(Tables.USER_IDS
|
qb.setTables(Tables.USER_IDS
|
||||||
+ " LEFT JOIN " + Tables.CERTS
|
+ " INNER JOIN " + Tables.KEY_RINGS + " ON ("
|
||||||
+ " ON ("
|
+ Tables.KEY_RINGS + "." + BaseColumns._ID + " = "
|
||||||
|
+ Tables.USER_IDS + "." + KeysColumns.KEY_RING_ROW_ID
|
||||||
|
+ ") LEFT JOIN " + Tables.CERTS + " ON ("
|
||||||
+ Tables.USER_IDS + "." + UserIds.KEY_RING_ROW_ID + " = "
|
+ Tables.USER_IDS + "." + UserIds.KEY_RING_ROW_ID + " = "
|
||||||
+ Tables.CERTS + "." + Certs.KEY_RING_ROW_ID
|
+ Tables.CERTS + "." + Certs.KEY_RING_ROW_ID
|
||||||
+ " AND " + Tables.USER_IDS + "." + UserIds.RANK + " = "
|
+ " AND " + Tables.USER_IDS + "." + UserIds.RANK + " = "
|
||||||
+ Tables.CERTS + "." + Certs.RANK
|
+ Tables.CERTS + "." + Certs.RANK
|
||||||
|
+ ") LEFT JOIN " + Tables.KEYS + " ON ("
|
||||||
|
+ Tables.KEYS + "." + Keys.KEY_ID + " = "
|
||||||
|
+ Tables.CERTS + "." + Certs.KEY_ID_CERTIFIER
|
||||||
|
// might introduce a "trusted" flag later? for now, we simply assume
|
||||||
|
// every private key's signature is good.
|
||||||
|
+ " AND " + Tables.KEYS + "." + Keys.TYPE
|
||||||
|
+ " == " + KeyTypes.SECRET
|
||||||
+ ")");
|
+ ")");
|
||||||
|
|
||||||
groupBy = Tables.USER_IDS + "." + UserIds.RANK;
|
groupBy = Tables.USER_IDS + "." + UserIds.RANK;
|
||||||
|
|
||||||
HashMap<String, String> pmap = new HashMap<String, String>();
|
qb.setProjectionMap(getProjectionMapForUserIds());
|
||||||
pmap.put(UserIds._ID, Tables.USER_IDS + "." + UserIds._ID);
|
|
||||||
pmap.put(UserIds.USER_ID, Tables.USER_IDS + "." + UserIds.USER_ID);
|
|
||||||
pmap.put(UserIds.RANK, Tables.USER_IDS + "." + UserIds.RANK);
|
|
||||||
pmap.put("verified", "COUNT(" + Tables.CERTS + "." + Certs._ID + ") AS verified");
|
|
||||||
qb.setProjectionMap(pmap);
|
|
||||||
|
|
||||||
qb.appendWhere(Tables.USER_IDS + "." + UserIdsColumns.KEY_RING_ROW_ID + " = ");
|
if(match == PUBLIC_KEY_RING_BY_MASTER_KEY_ID_USER_ID) {
|
||||||
qb.appendWhereEscapeString(uri.getPathSegments().get(2));
|
qb.appendWhere(Tables.KEY_RINGS + "." + KeyRingsColumns.MASTER_KEY_ID + " = ");
|
||||||
|
qb.appendWhereEscapeString(uri.getPathSegments().get(3));
|
||||||
|
} else {
|
||||||
|
qb.appendWhere(Tables.USER_IDS + "." + UserIdsColumns.KEY_RING_ROW_ID + " = ");
|
||||||
|
qb.appendWhereEscapeString(uri.getPathSegments().get(2));
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -728,7 +730,8 @@ public class KeychainProvider extends ContentProvider {
|
|||||||
+ "signer." + Keys.RANK + " = 0"
|
+ "signer." + Keys.RANK + " = 0"
|
||||||
+ ")");
|
+ ")");
|
||||||
|
|
||||||
// groupBy = Tables.USER_IDS + "." + UserIds.RANK;
|
groupBy = Tables.CERTS + "." + Certs.RANK + ", "
|
||||||
|
+ Tables.CERTS + "." + Certs.KEY_ID_CERTIFIER;
|
||||||
|
|
||||||
HashMap<String, String> pmap2 = new HashMap<String, String>();
|
HashMap<String, String> pmap2 = new HashMap<String, String>();
|
||||||
pmap2.put(Certs._ID, Tables.CERTS + "." + Certs._ID);
|
pmap2.put(Certs._ID, Tables.CERTS + "." + Certs._ID);
|
||||||
|
@ -207,7 +207,7 @@ public class ProviderHelper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// get a list of owned secret keys, for verification filtering
|
// get a list of owned secret keys, for verification filtering
|
||||||
Map<Long, PGPKeyRing> allKeyRings = getPGPKeyRings(context, KeyRings.buildPublicKeyRingsUri());
|
Map<Long, PGPKeyRing> allKeyRings = getPGPKeyRings(context, KeyRings.buildSecretKeyRingsUri());
|
||||||
|
|
||||||
int userIdRank = 0;
|
int userIdRank = 0;
|
||||||
for (String userId : new IterableIterator<String>(masterKey.getUserIDs())) {
|
for (String userId : new IterableIterator<String>(masterKey.getUserIDs())) {
|
||||||
@ -218,35 +218,34 @@ public class ProviderHelper {
|
|||||||
masterKey.getSignaturesForID(userId))) {
|
masterKey.getSignaturesForID(userId))) {
|
||||||
long certId = cert.getKeyID();
|
long certId = cert.getKeyID();
|
||||||
boolean verified = false;
|
boolean verified = false;
|
||||||
// only care for signatures from our own private keys
|
// do verify signatures from our own private keys
|
||||||
if(allKeyRings.containsKey(certId)) try {
|
if(allKeyRings.containsKey(certId)) try {
|
||||||
// mark them as verified
|
// mark them as verified
|
||||||
cert.init(new JcaPGPContentVerifierBuilderProvider().setProvider("SC"), allKeyRings.get(certId).getPublicKey());
|
cert.init(
|
||||||
|
new JcaPGPContentVerifierBuilderProvider().setProvider(
|
||||||
|
Constants.BOUNCY_CASTLE_PROVIDER_NAME),
|
||||||
|
allKeyRings.get(certId).getPublicKey());
|
||||||
verified = cert.verifyCertification(userId, masterKey);
|
verified = cert.verifyCertification(userId, masterKey);
|
||||||
// TODO: at this point, we only save signatures from available secret keys.
|
Log.d(Constants.TAG, "Verified sig for " + userId + " " + verified + " from "
|
||||||
// should we save all? those are quite a lot of rows for info we don't really
|
|
||||||
// use. I left it out for now - it is available from key servers, so we can
|
|
||||||
// always get it later.
|
|
||||||
Log.d(Constants.TAG, "sig for " + userId + " " + verified + " from "
|
|
||||||
+ PgpKeyHelper.convertKeyIdToHex(cert.getKeyID())
|
+ PgpKeyHelper.convertKeyIdToHex(cert.getKeyID())
|
||||||
);
|
);
|
||||||
operations.add(buildPublicCertOperations(
|
|
||||||
context, keyRingRowId, userIdRank, masterKey.getKeyID(), cert, verified));
|
|
||||||
} catch(SignatureException e) {
|
} catch(SignatureException e) {
|
||||||
Log.e(Constants.TAG, "Signature verification failed.", e);
|
Log.e(Constants.TAG, "Signature verification failed! "
|
||||||
} catch(PGPException e) {
|
|
||||||
Log.e(Constants.TAG, "Signature verification failed.", e);
|
|
||||||
} else {
|
|
||||||
Log.d(Constants.TAG, "ignored sig for "
|
|
||||||
+ PgpKeyHelper.convertKeyIdToHex(masterKey.getKeyID())
|
+ PgpKeyHelper.convertKeyIdToHex(masterKey.getKeyID())
|
||||||
+ " from "
|
+ " from "
|
||||||
+ PgpKeyHelper.convertKeyIdToHex(cert.getKeyID())
|
+ PgpKeyHelper.convertKeyIdToHex(cert.getKeyID()), e);
|
||||||
);
|
} catch(PGPException e) {
|
||||||
operations.add(buildPublicCertOperations(
|
Log.e(Constants.TAG, "Signature verification failed! "
|
||||||
context, keyRingRowId, userIdRank, masterKey.getKeyID(), cert, false));
|
+ PgpKeyHelper.convertKeyIdToHex(masterKey.getKeyID())
|
||||||
|
+ " from "
|
||||||
|
+ PgpKeyHelper.convertKeyIdToHex(cert.getKeyID()), e);
|
||||||
}
|
}
|
||||||
// if we wanted to save all, not just our own verifications
|
Log.d(Constants.TAG, "sig for " + userId + " from "
|
||||||
// buildPublicCertOperations(context, keyRingRowId, rank, cert, verified);
|
+ PgpKeyHelper.convertKeyIdToHex(cert.getKeyID())
|
||||||
|
);
|
||||||
|
// regardless of verification, save the certification
|
||||||
|
operations.add(buildPublicCertOperations(
|
||||||
|
context, keyRingRowId, userIdRank, masterKey.getKeyID(), cert, verified));
|
||||||
}
|
}
|
||||||
|
|
||||||
++userIdRank;
|
++userIdRank;
|
||||||
|
@ -43,6 +43,7 @@ import org.sufficientlysecure.keychain.helper.Preferences;
|
|||||||
import org.sufficientlysecure.keychain.pgp.PgpKeyHelper;
|
import org.sufficientlysecure.keychain.pgp.PgpKeyHelper;
|
||||||
import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException;
|
import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException;
|
||||||
import org.sufficientlysecure.keychain.provider.KeychainContract;
|
import org.sufficientlysecure.keychain.provider.KeychainContract;
|
||||||
|
import org.sufficientlysecure.keychain.provider.KeychainDatabase;
|
||||||
import org.sufficientlysecure.keychain.provider.ProviderHelper;
|
import org.sufficientlysecure.keychain.provider.ProviderHelper;
|
||||||
import org.sufficientlysecure.keychain.service.KeychainIntentService;
|
import org.sufficientlysecure.keychain.service.KeychainIntentService;
|
||||||
import org.sufficientlysecure.keychain.service.KeychainIntentServiceHandler;
|
import org.sufficientlysecure.keychain.service.KeychainIntentServiceHandler;
|
||||||
@ -164,7 +165,7 @@ public class CertifyKeyActivity extends ActionBarActivity implements
|
|||||||
KeychainContract.KeyRings._ID,
|
KeychainContract.KeyRings._ID,
|
||||||
KeychainContract.KeyRings.MASTER_KEY_ID,
|
KeychainContract.KeyRings.MASTER_KEY_ID,
|
||||||
KeychainContract.Keys.FINGERPRINT,
|
KeychainContract.Keys.FINGERPRINT,
|
||||||
KeychainContract.UserIds.USER_ID
|
KeychainContract.UserIds.USER_ID,
|
||||||
};
|
};
|
||||||
static final int INDEX_MASTER_KEY_ID = 1;
|
static final int INDEX_MASTER_KEY_ID = 1;
|
||||||
static final int INDEX_FINGERPRINT = 2;
|
static final int INDEX_FINGERPRINT = 2;
|
||||||
@ -174,10 +175,11 @@ public class CertifyKeyActivity extends ActionBarActivity implements
|
|||||||
new String[]{
|
new String[]{
|
||||||
KeychainContract.UserIds._ID,
|
KeychainContract.UserIds._ID,
|
||||||
KeychainContract.UserIds.USER_ID,
|
KeychainContract.UserIds.USER_ID,
|
||||||
KeychainContract.UserIds.RANK
|
KeychainContract.UserIds.RANK,
|
||||||
|
"verified"
|
||||||
};
|
};
|
||||||
static final String USER_IDS_SORT_ORDER =
|
static final String USER_IDS_SORT_ORDER =
|
||||||
KeychainContract.UserIds.RANK + " ASC";
|
KeychainDatabase.Tables.USER_IDS + "." + KeychainContract.UserIds.RANK + " ASC";
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
|
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
|
||||||
|
@ -53,12 +53,17 @@ public class ViewCertActivity extends ActionBarActivity
|
|||||||
KeychainContract.Certs._ID,
|
KeychainContract.Certs._ID,
|
||||||
KeychainContract.Certs.KEY_ID,
|
KeychainContract.Certs.KEY_ID,
|
||||||
KeychainContract.UserIds.USER_ID,
|
KeychainContract.UserIds.USER_ID,
|
||||||
KeychainContract.Certs.RANK,
|
|
||||||
KeychainContract.Certs.CREATION,
|
KeychainContract.Certs.CREATION,
|
||||||
KeychainContract.Certs.KEY_ID_CERTIFIER,
|
KeychainContract.Certs.KEY_ID_CERTIFIER,
|
||||||
"signer_uid",
|
"signer_uid",
|
||||||
KeychainContract.Certs.KEY_DATA
|
KeychainContract.Certs.KEY_DATA
|
||||||
};
|
};
|
||||||
|
private static final int INDEX_KEY_ID = 1;
|
||||||
|
private static final int INDEX_USER_ID = 2;
|
||||||
|
private static final int INDEX_CREATION = 3;
|
||||||
|
private static final int INDEX_KEY_ID_CERTIFIER = 4;
|
||||||
|
private static final int INDEX_UID_CERTIFIER = 5;
|
||||||
|
private static final int INDEX_KEY_DATA = 6;
|
||||||
|
|
||||||
private Uri mDataUri;
|
private Uri mDataUri;
|
||||||
|
|
||||||
@ -78,7 +83,6 @@ public class ViewCertActivity extends ActionBarActivity
|
|||||||
|
|
||||||
mSigneeKey = (TextView) findViewById(R.id.signee_key);
|
mSigneeKey = (TextView) findViewById(R.id.signee_key);
|
||||||
mSigneeUid = (TextView) findViewById(R.id.signee_uid);
|
mSigneeUid = (TextView) findViewById(R.id.signee_uid);
|
||||||
mRank = (TextView) findViewById(R.id.subkey_rank);
|
|
||||||
mAlgorithm = (TextView) findViewById(R.id.algorithm);
|
mAlgorithm = (TextView) findViewById(R.id.algorithm);
|
||||||
mType = (TextView) findViewById(R.id.signature_type);
|
mType = (TextView) findViewById(R.id.signature_type);
|
||||||
mCreation = (TextView) findViewById(R.id.creation);
|
mCreation = (TextView) findViewById(R.id.creation);
|
||||||
@ -108,29 +112,26 @@ public class ViewCertActivity extends ActionBarActivity
|
|||||||
@Override
|
@Override
|
||||||
public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
|
public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
|
||||||
if(data.moveToFirst()) {
|
if(data.moveToFirst()) {
|
||||||
String signeeKey = "0x" + PgpKeyHelper.convertKeyIdToHex(data.getLong(1));
|
String signeeKey = "0x" + PgpKeyHelper.convertKeyIdToHex(data.getLong(INDEX_KEY_ID));
|
||||||
mSigneeKey.setText(signeeKey);
|
mSigneeKey.setText(signeeKey);
|
||||||
|
|
||||||
String signeeUid = data.getString(2);
|
String signeeUid = data.getString(INDEX_USER_ID);
|
||||||
mSigneeUid.setText(signeeUid);
|
mSigneeUid.setText(signeeUid);
|
||||||
|
|
||||||
String subkey_rank = Integer.toString(data.getInt(3));
|
Date creationDate = new Date(data.getLong(INDEX_CREATION) * 1000);
|
||||||
mRank.setText(subkey_rank);
|
|
||||||
|
|
||||||
Date creationDate = new Date(data.getLong(4) * 1000);
|
|
||||||
mCreation.setText(DateFormat.getDateFormat(getApplicationContext()).format(creationDate));
|
mCreation.setText(DateFormat.getDateFormat(getApplicationContext()).format(creationDate));
|
||||||
|
|
||||||
mSignerKeyId = data.getLong(5);
|
mSignerKeyId = data.getLong(INDEX_KEY_ID_CERTIFIER);
|
||||||
String signerKey = "0x" + PgpKeyHelper.convertKeyIdToHex(mSignerKeyId);
|
String signerKey = "0x" + PgpKeyHelper.convertKeyIdToHex(mSignerKeyId);
|
||||||
mSignerKey.setText(signerKey);
|
mSignerKey.setText(signerKey);
|
||||||
|
|
||||||
String signerUid = data.getString(6);
|
String signerUid = data.getString(INDEX_UID_CERTIFIER);
|
||||||
if(signerUid != null)
|
if(signerUid != null)
|
||||||
mSignerUid.setText(signerUid);
|
mSignerUid.setText(signerUid);
|
||||||
else
|
else
|
||||||
mSignerUid.setText(R.string.unknown_uid);
|
mSignerUid.setText(R.string.unknown_uid);
|
||||||
|
|
||||||
byte[] sigData = data.getBlob(7);
|
byte[] sigData = data.getBlob(INDEX_KEY_DATA);
|
||||||
PGPSignature sig = PgpConversionHelper.BytesToPGPSignature(sigData);
|
PGPSignature sig = PgpConversionHelper.BytesToPGPSignature(sigData);
|
||||||
if(sig != null) {
|
if(sig != null) {
|
||||||
String algorithmStr = PgpKeyHelper.getAlgorithmInfo(sig.getKeyAlgorithm(), 0);
|
String algorithmStr = PgpKeyHelper.getAlgorithmInfo(sig.getKeyAlgorithm(), 0);
|
||||||
|
@ -198,22 +198,26 @@ public class ViewKeyMainFragment extends Fragment implements
|
|||||||
static final int KEYRING_INDEX_MASTER_KEY_ID = 1;
|
static final int KEYRING_INDEX_MASTER_KEY_ID = 1;
|
||||||
static final int KEYRING_INDEX_USER_ID = 2;
|
static final int KEYRING_INDEX_USER_ID = 2;
|
||||||
|
|
||||||
static final String[] USER_IDS_PROJECTION =
|
static final String[] USER_IDS_PROJECTION = new String[]{
|
||||||
new String[]{
|
KeychainContract.UserIds._ID,
|
||||||
KeychainContract.UserIds._ID,
|
KeychainContract.UserIds.USER_ID,
|
||||||
KeychainContract.UserIds.USER_ID,
|
KeychainContract.UserIds.RANK,
|
||||||
KeychainContract.UserIds.RANK,
|
"verified",
|
||||||
};
|
};
|
||||||
|
// not the main user id
|
||||||
|
static final String USER_IDS_SELECTION =
|
||||||
|
KeychainDatabase.Tables.USER_IDS + "." + KeychainContract.UserIds.RANK + " > 0 ";
|
||||||
static final String USER_IDS_SORT_ORDER =
|
static final String USER_IDS_SORT_ORDER =
|
||||||
KeychainContract.UserIds.RANK + " COLLATE LOCALIZED ASC";
|
KeychainDatabase.Tables.USER_IDS + "." + KeychainContract.UserIds.RANK + " COLLATE LOCALIZED ASC";
|
||||||
|
|
||||||
static final String[] KEYS_PROJECTION =
|
static final String[] KEYS_PROJECTION = new String[]{
|
||||||
new String[]{KeychainContract.Keys._ID, KeychainContract.Keys.KEY_ID,
|
KeychainContract.Keys._ID, KeychainContract.Keys.KEY_ID,
|
||||||
KeychainContract.Keys.IS_MASTER_KEY, KeychainContract.Keys.ALGORITHM,
|
KeychainContract.Keys.IS_MASTER_KEY, KeychainContract.Keys.ALGORITHM,
|
||||||
KeychainContract.Keys.KEY_SIZE, KeychainContract.Keys.CAN_CERTIFY,
|
KeychainContract.Keys.KEY_SIZE, KeychainContract.Keys.CAN_CERTIFY,
|
||||||
KeychainContract.Keys.CAN_SIGN, KeychainContract.Keys.CAN_ENCRYPT,
|
KeychainContract.Keys.CAN_SIGN, KeychainContract.Keys.CAN_ENCRYPT,
|
||||||
KeychainContract.Keys.CREATION, KeychainContract.Keys.EXPIRY,
|
KeychainContract.Keys.CREATION, KeychainContract.Keys.EXPIRY,
|
||||||
KeychainContract.Keys.FINGERPRINT};
|
KeychainContract.Keys.FINGERPRINT
|
||||||
|
};
|
||||||
static final String KEYS_SORT_ORDER = KeychainContract.Keys.RANK + " ASC";
|
static final String KEYS_SORT_ORDER = KeychainContract.Keys.RANK + " ASC";
|
||||||
static final int KEYS_INDEX_ID = 0;
|
static final int KEYS_INDEX_ID = 0;
|
||||||
static final int KEYS_INDEX_KEY_ID = 1;
|
static final int KEYS_INDEX_KEY_ID = 1;
|
||||||
|
@ -60,24 +60,6 @@
|
|||||||
android:paddingRight="5dip" />
|
android:paddingRight="5dip" />
|
||||||
</TableRow>
|
</TableRow>
|
||||||
|
|
||||||
<TableRow
|
|
||||||
android:layout_width="fill_parent"
|
|
||||||
android:layout_height="fill_parent">
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_gravity="top"
|
|
||||||
android:paddingRight="10dip"
|
|
||||||
android:text="@string/label_subkey_rank" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/subkey_rank"
|
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:paddingRight="5dip" />
|
|
||||||
</TableRow>
|
|
||||||
|
|
||||||
<TableRow
|
<TableRow
|
||||||
android:layout_width="fill_parent"
|
android:layout_width="fill_parent"
|
||||||
android:layout_height="fill_parent">
|
android:layout_height="fill_parent">
|
||||||
|
Loading…
Reference in New Issue
Block a user