cleanup syncInfoActivity and layouts

pull/5/head
Felix Prahl-Kamps 2019-07-03 14:50:43 +02:00
parent a9498f45f1
commit 9268a0939c
26 changed files with 437 additions and 604 deletions

View File

@ -15,8 +15,6 @@
android:supportsRtl="true"
android:theme="@style/AppTheme"
tools:ignore="GoogleAppIndexingWarning">
<activity android:name=".activities.ExchangeActivity"></activity>
<activity android:name=".activities.SyncActivity2" />
<activity android:name=".activities.StartUpActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
@ -31,7 +29,7 @@
android:name=".activities.HomeActivity"
android:label="@string/app_name" />
<activity
android:name=".activities.SyncActivity"
android:name=".activities.ExchangeActivity"
android:configChanges="orientation|screenSize"
android:parentActivityName=".activities.HomeActivity"
android:screenOrientation="portrait"

View File

@ -56,7 +56,7 @@ public class ExchangeActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_sync);
setContentView(R.layout.activity_exchange);
preferenceManager = PreferenceManager.getInstance(ExchangeActivity.this);
qrCodeGenerator = new QrCodeGenerator(ExchangeActivity.this);
@ -259,7 +259,8 @@ public class ExchangeActivity extends AppCompatActivity {
case DATA_EXCHANGE:
try {
final SyncInformation remoteSyncInfo = new Gson().fromJson(diffieHellman.decrypt(qrData), SyncInformation.class);
List<UploadInformation> uploadInformationList = preferenceManager.getUploadInformationList();
final List<UploadInformation> uploadInformationList = preferenceManager.getUploadInformationList();
for (final UploadInformation ui : uploadInformationList) {
if (ui.getRemote().organisation.uuid.equals(remoteSyncInfo.organisation.uuid)) {
@ -274,7 +275,8 @@ public class ExchangeActivity extends AppCompatActivity {
@Override
public void negative() {
// replace credentials too
preferenceManager.removeUploadInformation(ui.getUuid());
uploadInformationList.remove(ui);
preferenceManager.setUploadInformationList(uploadInformationList);
}
});

View File

@ -1,357 +0,0 @@
package lu.circl.mispbump.activities;
import android.content.Intent;
import android.content.res.ColorStateList;
import android.graphics.Bitmap;
import android.os.Bundle;
import android.view.View;
import android.widget.FrameLayout;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.appcompat.app.AppCompatActivity;
import androidx.coordinatorlayout.widget.CoordinatorLayout;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentTransaction;
import com.google.android.material.snackbar.Snackbar;
import com.google.gson.Gson;
import com.google.gson.JsonSyntaxException;
import java.security.NoSuchAlgorithmException;
import java.security.PublicKey;
import java.security.spec.InvalidKeySpecException;
import java.util.List;
import lu.circl.mispbump.R;
import lu.circl.mispbump.auxiliary.DialogManager;
import lu.circl.mispbump.auxiliary.PreferenceManager;
import lu.circl.mispbump.auxiliary.QrCodeGenerator;
import lu.circl.mispbump.auxiliary.RandomString;
import lu.circl.mispbump.fragments.CameraFragment;
import lu.circl.mispbump.models.SyncInformation;
import lu.circl.mispbump.models.UploadInformation;
import lu.circl.mispbump.security.DiffieHellman;
public class SyncActivity extends AppCompatActivity {
enum SyncState {
PUBLIC_KEY,
DATA
}
enum UiState {
PUBLIC_KEY_SHOW,
PUBLIC_KEY_SHOW_AND_RECEIVED,
SYNC_INFO_SHOW,
SYNC_INFO_SHOW_AND_RECEIVED
}
private SyncState currentSyncState;
private PreferenceManager preferenceManager;
private UploadInformation uploadInformation;
private QrCodeGenerator qrCodeGenerator;
private DiffieHellman diffieHellman;
private boolean foreignPublicKeyReceived, foreignSyncInfoReceived;
// Fragments
private CameraFragment cameraFragment;
// Views
private CoordinatorLayout rootLayout;
private FrameLayout qrFrame;
private ImageView qrCode;
private TextView qrHint;
private ImageButton prevButton, nextButton;
private Bitmap publicKeyQrCode, syncInfoQrCode;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_sync);
init();
initViews();
switchState(SyncState.PUBLIC_KEY);
}
@Override
public void onBackPressed() {
super.onBackPressed();
switch (currentSyncState) {
case PUBLIC_KEY:
// TODO warn that sync is maybe not complete ... ?
break;
case DATA:
switchState(SyncState.PUBLIC_KEY);
break;
}
}
private void init() {
preferenceManager = PreferenceManager.getInstance(SyncActivity.this);
diffieHellman = DiffieHellman.getInstance();
qrCodeGenerator = new QrCodeGenerator(SyncActivity.this);
publicKeyQrCode = qrCodeGenerator.generateQrCode(DiffieHellman.publicKeyToString(diffieHellman.getPublicKey()));
uploadInformation = new UploadInformation();
}
private void initViews() {
rootLayout = findViewById(R.id.rootLayout);
qrFrame = findViewById(R.id.qrFrame);
qrCode = findViewById(R.id.qrCode);
qrHint = findViewById(R.id.qrInfo);
prevButton = findViewById(R.id.prevButton);
prevButton.setOnClickListener(onPrevClicked);
nextButton = findViewById(R.id.nextButton);
nextButton.setOnClickListener(onNextClicked);
}
private void switchState(SyncState state) {
switchFragment(state);
displayQr(state);
switch (state) {
case PUBLIC_KEY:
if (foreignPublicKeyReceived) {
switchUiState(UiState.PUBLIC_KEY_SHOW_AND_RECEIVED);
cameraFragment.setReadQrEnabled(false);
} else {
switchUiState(UiState.PUBLIC_KEY_SHOW);
cameraFragment.setReadQrEnabled(true);
}
break;
case DATA:
if (foreignSyncInfoReceived) {
switchUiState(UiState.SYNC_INFO_SHOW_AND_RECEIVED);
cameraFragment.setReadQrEnabled(false);
} else {
switchUiState(UiState.SYNC_INFO_SHOW);
cameraFragment.setReadQrEnabled(true);
}
break;
}
currentSyncState = state;
}
private void switchFragment(SyncState state) {
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
String camTag = CameraFragment.class.getSimpleName();
switch (state) {
case PUBLIC_KEY:
case DATA:
cameraFragment = (CameraFragment) fragmentManager.findFragmentByTag(camTag);
if (cameraFragment != null) {
fragmentTransaction.show(cameraFragment);
} else {
cameraFragment = new CameraFragment();
cameraFragment.setOnQrAvailableListener(onReadQrCode);
fragmentTransaction.add(R.id.fragmentContainer, cameraFragment, camTag);
}
fragmentTransaction.commit();
break;
}
}
private void displayQr(SyncState state) {
switch (state) {
case PUBLIC_KEY:
qrCode.setImageBitmap(publicKeyQrCode);
qrFrame.setVisibility(View.VISIBLE);
break;
case DATA:
qrCode.setImageBitmap(syncInfoQrCode);
qrFrame.setVisibility(View.VISIBLE);
break;
}
}
private void switchUiState(final UiState state) {
runOnUiThread(new Runnable() {
@Override
public void run() {
switch (state) {
case PUBLIC_KEY_SHOW:
prevButton.setImageDrawable(getDrawable(R.drawable.ic_close));
prevButton.setVisibility(View.VISIBLE);
nextButton.setVisibility(View.INVISIBLE);
qrReceivedFeedback(false);
break;
case PUBLIC_KEY_SHOW_AND_RECEIVED:
prevButton.setImageDrawable(getDrawable(R.drawable.ic_close));
nextButton.setImageDrawable(getDrawable(R.drawable.ic_arrow_forward));
prevButton.setVisibility(View.VISIBLE);
nextButton.setVisibility(View.VISIBLE);
// cameraFragment.disablePreview();
qrReceivedFeedback(true);
break;
case SYNC_INFO_SHOW:
prevButton.setImageDrawable(getDrawable(R.drawable.ic_arrow_back));
nextButton.setImageDrawable(getDrawable(R.drawable.ic_arrow_forward));
nextButton.setVisibility(View.INVISIBLE);
prevButton.setVisibility(View.VISIBLE);
// cameraFragment.enablePreview();
qrReceivedFeedback(false);
break;
case SYNC_INFO_SHOW_AND_RECEIVED:
prevButton.setImageDrawable(getDrawable(R.drawable.ic_arrow_back));
nextButton.setImageDrawable(getDrawable(R.drawable.ic_check));
nextButton.setVisibility(View.VISIBLE);
prevButton.setVisibility(View.VISIBLE);
// cameraFragment.disablePreview();
qrReceivedFeedback(true);
break;
}
}
});
}
// listener
private View.OnClickListener onPrevClicked = new View.OnClickListener() {
@Override
public void onClick(View v) {
switch (currentSyncState) {
case PUBLIC_KEY:
finish();
break;
case DATA:
switchState(SyncState.PUBLIC_KEY);
break;
}
}
};
private View.OnClickListener onNextClicked = new View.OnClickListener() {
@Override
public void onClick(View v) {
switch (currentSyncState) {
case PUBLIC_KEY:
switchState(SyncState.DATA);
break;
case DATA:
uploadInformation.setCurrentSyncStatus(UploadInformation.SyncStatus.PENDING);
preferenceManager.addUploadInformation(uploadInformation);
Intent i = new Intent(SyncActivity.this, UploadInfoActivity.class);
i.putExtra(UploadInfoActivity.EXTRA_UPLOAD_INFO_UUID, uploadInformation.getUuid());
startActivity(i);
finish();
break;
}
}
};
private CameraFragment.QrScanCallback onReadQrCode = new CameraFragment.QrScanCallback() {
@Override
public void qrScanResult(String qrData) {
cameraFragment.setReadQrEnabled(false);
switch (currentSyncState) {
case PUBLIC_KEY:
try {
final PublicKey pk = DiffieHellman.publicKeyFromString(qrData);
diffieHellman.setForeignPublicKey(pk);
syncInfoQrCode = generateSyncInfoQr();
switchUiState(UiState.PUBLIC_KEY_SHOW_AND_RECEIVED);
foreignPublicKeyReceived = true;
} catch (InvalidKeySpecException | NoSuchAlgorithmException e) {
Snackbar.make(rootLayout, "Invalid key", Snackbar.LENGTH_SHORT).show();
switchUiState(UiState.PUBLIC_KEY_SHOW);
}
break;
case DATA:
try {
final SyncInformation remoteSyncInfo = new Gson().fromJson(diffieHellman.decrypt(qrData), SyncInformation.class);
List<UploadInformation> uploadInformationList = preferenceManager.getUploadInformationList();
if (uploadInformationList != null) {
for (final UploadInformation ui : uploadInformationList) {
if (ui.getRemote().organisation.uuid.equals(remoteSyncInfo.organisation.uuid)) {
// DialogManager.syncAlreadyExistsDialog(SyncActivity.this, new DialogManager.IDialogFeedback() {
// @Override
// public void positive() {
// uploadInformation.setUuid(ui.getUuid());
// }
//
// @Override
// public void negative() {
// finish();
// }
// });
}
}
}
uploadInformation.setRemote(remoteSyncInfo);
switchUiState(UiState.SYNC_INFO_SHOW_AND_RECEIVED);
foreignSyncInfoReceived = true;
} catch (JsonSyntaxException e) {
Snackbar.make(rootLayout, "Sync information unreadable", Snackbar.LENGTH_SHORT).show();
switchUiState(UiState.SYNC_INFO_SHOW);
}
break;
}
}
};
// aux
private SyncInformation generateLocalSyncInfo() {
SyncInformation syncInformation = new SyncInformation();
syncInformation.organisation = preferenceManager.getUserOrganisation().toSyncOrganisation();
syncInformation.syncUserAuthkey = new RandomString(40).nextString();
syncInformation.baseUrl = preferenceManager.getServerUrl();
syncInformation.syncUserPassword = new RandomString(16).nextString();
syncInformation.syncUserEmail = preferenceManager.getUserInfo().email;
return syncInformation;
}
private Bitmap generateSyncInfoQr() {
SyncInformation syncInformation = generateLocalSyncInfo();
uploadInformation.setLocal(syncInformation);
// encrypt serialized content
String encrypted = diffieHellman.encrypt(new Gson().toJson(syncInformation));
// generate QR code
return qrCodeGenerator.generateQrCode(encrypted);
}
private void qrReceivedFeedback(final boolean done) {
runOnUiThread(new Runnable() {
@Override
public void run() {
if (done) {
qrHint.setCompoundDrawablesWithIntrinsicBounds(getDrawable(R.drawable.ic_check_outline), null, null, null);
qrHint.setCompoundDrawableTintList(ColorStateList.valueOf(getColor(R.color.status_green)));
} else {
qrHint.setCompoundDrawablesWithIntrinsicBounds(getDrawable(R.drawable.ic_info_outline), null, null, null);
qrHint.setCompoundDrawableTintList(ColorStateList.valueOf(getColor(R.color.status_amber)));
}
}
});
}
}

View File

@ -1,14 +1,10 @@
package lu.circl.mispbump.activities;
import android.content.Intent;
import android.content.res.ColorStateList;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
@ -27,27 +23,30 @@ import java.util.UUID;
import lu.circl.mispbump.R;
import lu.circl.mispbump.auxiliary.PreferenceManager;
import lu.circl.mispbump.fragments.UploadInfoFragment;
import lu.circl.mispbump.fragments.UploadCredentialsFragment;
import lu.circl.mispbump.fragments.UploadSettingsFragment;
import lu.circl.mispbump.models.UploadInformation;
public class UploadInfoActivity extends AppCompatActivity {
public static String EXTRA_UPLOAD_INFO_UUID = "uploadInformation";
public static String EXTRA_UPLOAD_INFO_UUID = "uploadInformationUuid";
private PreferenceManager preferenceManager;
private UploadInformation uploadInformation;
private ViewPagerAdapter viewPagerAdapter;
private FloatingActionButton fab;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_upload_information_2);
setContentView(R.layout.activity_upload_information);
preferenceManager = PreferenceManager.getInstance(UploadInfoActivity.this);
// tint statusBar
getWindow().setStatusBarColor(getColor(R.color.grey_light));
getWindow().setStatusBarColor(getColor(R.color.white));
getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);
parseExtra();
@ -56,6 +55,23 @@ public class UploadInfoActivity extends AppCompatActivity {
initViews();
}
@Override
protected void onResume() {
super.onResume();
// refresh current uploadInformation
if (uploadInformation != null) {
uploadInformation = preferenceManager.getUploadInformation(uploadInformation.getUuid());
initContent();
}
}
@Override
public void onBackPressed() {
super.onBackPressed();
saveCurrentSettings();
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.menu_upload_info, menu);
@ -79,22 +95,6 @@ public class UploadInfoActivity extends AppCompatActivity {
}
}
@Override
protected void onResume() {
super.onResume();
// refresh current uploadInformation
if (uploadInformation != null) {
uploadInformation = preferenceManager.getUploadInformation(uploadInformation.getUuid());
}
}
@Override
public void onBackPressed() {
super.onBackPressed();
saveCurrentSettings();
}
private void parseExtra() {
Intent i = getIntent();
@ -114,47 +114,9 @@ public class UploadInfoActivity extends AppCompatActivity {
ActionBar ab = getSupportActionBar();
assert ab != null;
TextView tv = findViewById(R.id.syncStatus);
int statusColor;
String statusText;
Drawable statusDrawable;
switch (uploadInformation.getCurrentSyncStatus()) {
case COMPLETE:
statusColor = getColor(R.color.status_green);
statusText = "Successfully uploaded";
statusDrawable = getDrawable(R.drawable.ic_check_outline);
break;
case FAILURE:
statusColor = getColor(R.color.status_red);
statusText = "Error while uploading";
statusDrawable = getDrawable(R.drawable.ic_error_outline);
break;
case PENDING:
statusColor = getColor(R.color.status_amber);
statusText = "Not uploaded yet";
statusDrawable = getDrawable(R.drawable.ic_pending);
break;
default:
statusColor = getColor(R.color.status_green);
statusText = "Successfully uploaded";
statusDrawable = getDrawable(R.drawable.ic_check_outline);
break;
}
tv.setText(statusText);
tv.setTextColor(statusColor);
tv.setCompoundDrawablesWithIntrinsicBounds(null, null, statusDrawable, null);
tv.setCompoundDrawableTintList(ColorStateList.valueOf(statusColor));
ab.setTitle(uploadInformation.getRemote().organisation.name);
ab.setHomeAsUpIndicator(R.drawable.ic_close);
ab.setDisplayShowTitleEnabled(true);
ab.setDisplayShowCustomEnabled(false);
ab.setDisplayHomeAsUpEnabled(true);
}
@ -163,18 +125,19 @@ public class UploadInfoActivity extends AppCompatActivity {
TabLayout tabLayout = findViewById(R.id.tabLayout);
viewPagerAdapter = new ViewPagerAdapter(getSupportFragmentManager(), uploadInformation);
viewPager.setAdapter(viewPagerAdapter);
viewPager.addOnPageChangeListener(onPageChangeListener());
tabLayout.setupWithViewPager(viewPager);
}
private void initViews() {
FloatingActionButton fab = findViewById(R.id.fab);
fab = findViewById(R.id.fab);
fab.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// for the UploadActivity to have the latest settings of this UploadInfoObject
saveCurrentSettings();
Intent i = new Intent(UploadInfoActivity.this, UploadActivity.class);
@ -184,6 +147,26 @@ public class UploadInfoActivity extends AppCompatActivity {
});
}
private void initContent() {
switch (uploadInformation.getCurrentSyncStatus()) {
case COMPLETE:
break;
case FAILURE:
break;
case PENDING:
break;
default:
break;
}
}
private void saveCurrentSettings() {
uploadInformation.setAllowSelfSigned(viewPagerAdapter.uploadSettingsFragment.getAllowSelfSigned());
uploadInformation.setPull(viewPagerAdapter.uploadSettingsFragment.getPull());
@ -194,14 +177,39 @@ public class UploadInfoActivity extends AppCompatActivity {
}
private ViewPager.OnPageChangeListener onPageChangeListener() {
return new ViewPager.OnPageChangeListener() {
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
if (position == 0) {
float scale = (1 - positionOffset);
fab.setScaleX(scale);
fab.setScaleY(scale);
}
}
@Override
public void onPageSelected(int position) {
}
@Override
public void onPageScrollStateChanged(int state) {
}
};
}
class ViewPagerAdapter extends FragmentPagerAdapter {
private UploadSettingsFragment uploadSettingsFragment;
private UploadInfoFragment uploadInfoFragment = new UploadInfoFragment();
private UploadCredentialsFragment uploadCredentialsFragment;
ViewPagerAdapter(@NonNull FragmentManager fm, UploadInformation uploadInformation) {
super(fm, ViewPagerAdapter.BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT);
uploadSettingsFragment = new UploadSettingsFragment(uploadInformation);
uploadCredentialsFragment = new UploadCredentialsFragment(uploadInformation);
}
@NonNull
@ -212,7 +220,7 @@ public class UploadInfoActivity extends AppCompatActivity {
return uploadSettingsFragment;
case 1:
return uploadInfoFragment;
return uploadCredentialsFragment;
default:
uploadSettingsFragment = new UploadSettingsFragment();
@ -225,7 +233,7 @@ public class UploadInfoActivity extends AppCompatActivity {
public CharSequence getPageTitle(int position) {
switch (position) {
case 0:
return "Permissions";
return "Settings";
case 1:
return "Credentials";

View File

@ -0,0 +1,94 @@
package lu.circl.mispbump.customViews;
import android.content.Context;
import android.content.res.TypedArray;
import android.text.method.PasswordTransformationMethod;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.ImageButton;
import android.widget.TextView;
import androidx.constraintlayout.widget.ConstraintLayout;
import lu.circl.mispbump.R;
public class MaterialPasswordView extends ConstraintLayout {
private TextView titleView, passwordView;
private OnCopyClickListener onCopyClickListener;
public MaterialPasswordView(Context context, AttributeSet attrs) {
super(context, attrs);
View view = LayoutInflater.from(context).inflate(R.layout.material_password_view, this);
TypedArray a = getContext().obtainStyledAttributes(attrs, R.styleable.MaterialPasswordView);
final String title = a.getString(R.styleable.MaterialPasswordView_title);
final String password = a.getString(R.styleable.MaterialPasswordView_password);
a.recycle();
ImageButton copyButton = view.findViewById(R.id.copy);
copyButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
onCopyClickListener.onClick(title, getPassword());
}
});
titleView = view.findViewById(R.id.material_password_title);
titleView.setText(title);
passwordView = view.findViewById(R.id.material_password);
passwordView.setTransformationMethod(new PasswordTransformationMethod());
passwordView.setText(password);
ImageButton visibleToggle = findViewById(R.id.visibleToggle);
visibleToggle.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
if (passwordView.getTransformationMethod() == null) {
passwordView.setTransformationMethod(new PasswordTransformationMethod());
} else {
passwordView.setTransformationMethod(null);
}
}
});
}
public void setTitle(String title) {
titleView.setText(title);
}
public String getTitle() {
return titleView.getText().toString();
}
public void setPassword(String password) {
passwordView.setText(password);
}
public String getPassword() {
return passwordView.getText().toString();
}
public void setPasswordVisible(boolean visible) {
if (!visible) {
passwordView.setTransformationMethod(new PasswordTransformationMethod());
} else {
passwordView.setTransformationMethod(null);
}
}
public void addOnCopyClickedListener(OnCopyClickListener listener) {
onCopyClickListener = listener;
}
public interface OnCopyClickListener {
void onClick(String title, String password);
}
}

View File

@ -2,18 +2,16 @@ package lu.circl.mispbump.customViews;
import android.content.Context;
import android.content.res.TypedArray;
import androidx.annotation.Nullable;
import androidx.constraintlayout.widget.ConstraintLayout;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.annotation.Nullable;
import androidx.constraintlayout.widget.ConstraintLayout;
import lu.circl.mispbump.R;
public class MaterialPreferenceText extends ConstraintLayout {
@ -33,7 +31,12 @@ public class MaterialPreferenceText extends ConstraintLayout {
TypedArray a = getContext().obtainStyledAttributes(attrs, R.styleable.MaterialPreferenceText);
icon = view.findViewById(R.id.material_preference_src);
icon.setImageResource(a.getResourceId(R.styleable.MaterialPreferenceText_pref_icon, 0x0));
int imageRes = a.getResourceId(R.styleable.MaterialPreferenceText_pref_icon, 0x0);
if (imageRes != 0x0){
icon.setImageResource(imageRes);
} else {
icon.setVisibility(GONE);
}
title = view.findViewById(R.id.material_preference_title);
title.setText(a.getString(R.styleable.MaterialPreferenceText_title));

View File

@ -10,7 +10,6 @@ import android.widget.ImageView;
import android.widget.ProgressBar;
import android.widget.TextView;
import androidx.appcompat.widget.LinearLayoutCompat;
import androidx.constraintlayout.widget.ConstraintLayout;
import androidx.core.widget.ImageViewCompat;
@ -42,7 +41,7 @@ public class UploadAction extends ConstraintLayout {
super(context, attrs);
this.context = context;
View baseView = LayoutInflater.from(context).inflate(R.layout.view_upload_action_2, this);
View baseView = LayoutInflater.from(context).inflate(R.layout.view_upload_action, this);
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.UploadAction);

View File

@ -0,0 +1,62 @@
package lu.circl.mispbump.fragments;
import android.content.ClipData;
import android.content.ClipboardManager;
import android.content.Context;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import androidx.fragment.app.Fragment;
import com.google.android.material.snackbar.Snackbar;
import lu.circl.mispbump.R;
import lu.circl.mispbump.customViews.MaterialPasswordView;
import lu.circl.mispbump.customViews.MaterialPreferenceText;
import lu.circl.mispbump.models.UploadInformation;
public class UploadCredentialsFragment extends Fragment {
private View rootLayout;
private UploadInformation uploadInformation;
public UploadCredentialsFragment() {}
public UploadCredentialsFragment(UploadInformation uploadInformation) {
this.uploadInformation = uploadInformation;
}
private MaterialPasswordView.OnCopyClickListener onCopyClickListener = new MaterialPasswordView.OnCopyClickListener() {
@Override
public void onClick(String title, String password) {
ClipboardManager clipboard = (ClipboardManager) getActivity().getSystemService(Context.CLIPBOARD_SERVICE);
ClipData clip = ClipData.newPlainText(title, password);
clipboard.setPrimaryClip(clip);
Snackbar.make(rootLayout, "Copied to clipboard", Snackbar.LENGTH_LONG).show();
}
};
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.fragment_upload_credentials, container, false);
rootLayout = v.findViewById(R.id.rootLayout);
MaterialPreferenceText baseUrl = v.findViewById(R.id.baseUrl);
baseUrl.setSubtitle(uploadInformation.getRemote().baseUrl);
MaterialPasswordView authkey = v.findViewById(R.id.authkey);
authkey.setPassword(uploadInformation.getRemote().syncUserAuthkey);
authkey.addOnCopyClickedListener(onCopyClickListener);
MaterialPasswordView password = v.findViewById(R.id.password);
password.setPassword(uploadInformation.getRemote().syncUserPassword);
password.addOnCopyClickedListener(onCopyClickListener);
return v;
}
}

View File

@ -1,5 +1,5 @@
<vector android:height="24dp" android:tint="#FFFFFF"
android:viewportHeight="24.0" android:viewportWidth="24.0"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="#FF000000" android:pathData="M19.35,10.04C18.67,6.59 15.64,4 12,4 9.11,4 6.6,5.64 5.35,8.04 2.34,8.36 0,10.91 0,14c0,3.31 2.69,6 6,6h13c2.76,0 5,-2.24 5,-5 0,-2.64 -2.05,-4.78 -4.65,-4.96zM14,13v4h-4v-4H7l5,-5 5,5h-3z"/>
<path android:fillColor="#FFF" android:pathData="M19.35,10.04C18.67,6.59 15.64,4 12,4 9.11,4 6.6,5.64 5.35,8.04 2.34,8.36 0,10.91 0,14c0,3.31 2.69,6 6,6h13c2.76,0 5,-2.24 5,-5 0,-2.64 -2.05,-4.78 -4.65,-4.96zM14,13v4h-4v-4H7l5,-5 5,5h-3z"/>
</vector>

View File

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="#FF000000"
android:pathData="M12,4.5C7,4.5 2.73,7.61 1,12c1.73,4.39 6,7.5 11,7.5s9.27,-3.11 11,-7.5c-1.73,-4.39 -6,-7.5 -11,-7.5zM12,17c-2.76,0 -5,-2.24 -5,-5s2.24,-5 5,-5 5,2.24 5,5 -2.24,5 -5,5zM12,9c-1.66,0 -3,1.34 -3,3s1.34,3 3,3 3,-1.34 3,-3 -1.34,-3 -3,-3z"/>
</vector>

View File

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="#FF000000"
android:pathData="M15,1L4,1c-1.1,0 -2,0.9 -2,2v13c0,0.55 0.45,1 1,1s1,-0.45 1,-1L4,4c0,-0.55 0.45,-1 1,-1h10c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1zM15.59,5.59l4.83,4.83c0.37,0.37 0.58,0.88 0.58,1.41L21,21c0,1.1 -0.9,2 -2,2L7.99,23C6.89,23 6,22.1 6,21l0.01,-14c0,-1.1 0.89,-2 1.99,-2h6.17c0.53,0 1.04,0.21 1.42,0.59zM15,12h4.5L14,6.5L14,11c0,0.55 0.45,1 1,1z"/>
</vector>

View File

@ -6,6 +6,7 @@
android:id="@+id/rootLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:animateLayoutChanges="true"
tools:context=".activities.UploadActivity">
<com.google.android.material.appbar.AppBarLayout
@ -25,15 +26,14 @@
app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
android:layout_height="match_parent"
android:animateLayoutChanges="true">
<lu.circl.mispbump.customViews.UploadAction
android:id="@+id/availableAction"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginTop="16dp"
android:layout_marginEnd="16dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintEnd_toEndOf="parent"
@ -43,9 +43,7 @@
android:id="@+id/orgAction"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginTop="16dp"
android:layout_marginEnd="16dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintEnd_toEndOf="parent"
@ -55,9 +53,7 @@
android:id="@+id/userAction"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginTop="16dp"
android:layout_marginEnd="16dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
@ -67,9 +63,7 @@
android:id="@+id/serverAction"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginTop="16dp"
android:layout_marginEnd="16dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"

View File

@ -2,7 +2,6 @@
<androidx.coordinatorlayout.widget.CoordinatorLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/rootLayout"
android:layout_width="match_parent"
android:layout_height="match_parent">
@ -19,21 +18,6 @@
app:popupTheme="@style/PopupTheme"
app:theme="@style/ToolbarTheme.Light"/>
<TextView
android:id="@+id/syncStatus"
android:layout_marginTop="-12dp"
android:layout_marginBottom="8dp"
tools:text="Successfully uploaded"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="@style/TextAppearance.AppCompat.Widget.ActionBar.Subtitle"
android:textColor="@color/status_green"
android:gravity="center_vertical"
android:layout_marginStart="72dp"
android:drawableEnd="@drawable/ic_check_outline"
android:drawableTint="@color/status_green"
android:drawablePadding="8dp"/>
<com.google.android.material.tabs.TabLayout
android:id="@+id/tabLayout"
android:layout_width="match_parent"
@ -50,6 +34,7 @@
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/fab"
android:src="@drawable/ic_cloud_upload"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="end|bottom"

View File

@ -1,26 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:id="@+id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:drawablePadding="8dp"
android:lines="1"
android:textAppearance="@style/TextAppearance.AppCompat.Widget.ActionBar.Title"
tools:drawableEnd="@drawable/ic_error_outline"
tools:drawableTint="@color/status_red"
tools:text="Sample title"/>
<ImageView
android:src="@drawable/ic_error_outline"
android:tint="@color/status_red"
android:layout_width="24dp"
android:layout_height="24dp"/>
</LinearLayout>

View File

@ -0,0 +1,38 @@
<?xml version="1.0" encoding="utf-8"?>
<ScrollView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/rootLayout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<lu.circl.mispbump.customViews.MaterialPreferenceText
android:id="@+id/baseUrl"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
app:subtitle="www.google.de"
app:title="Base URL"/>
<lu.circl.mispbump.customViews.MaterialPasswordView
android:id="@+id/authkey"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
app:title="Authkey"
app:password="abc"/>
<lu.circl.mispbump.customViews.MaterialPasswordView
android:id="@+id/password"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
app:title="Password"
app:password="abc"/>
</LinearLayout>
</ScrollView>

View File

@ -2,7 +2,6 @@
<androidx.coordinatorlayout.widget.CoordinatorLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/rootLayout"
android:layout_width="match_parent"
android:layout_height="match_parent">
@ -20,7 +19,7 @@
android:layout_marginTop="16dp"
android:layout_marginEnd="16dp"
android:text="This Organisation will have the following rights on your MISP instance"
android:textAppearance="@style/Text.Title"
android:textAppearance="@style/TextAppearance.MaterialComponents.Overline"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"/>

View File

@ -0,0 +1,64 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/rootLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="16dp"
android:clickable="true"
android:focusable="true"
android:focusableInTouchMode="false"
android:foreground="?attr/selectableItemBackgroundBorderless"
android:animateLayoutChanges="true">
<ImageButton
android:id="@+id/visibleToggle"
android:layout_width="48dp"
android:layout_height="0dp"
android:background="?attr/selectableItemBackgroundBorderless"
android:src="@drawable/ic_eye"
android:tint="@color/colorPrimaryDark"
app:layout_constraintBottom_toBottomOf="@+id/material_password"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<ImageButton
android:id="@+id/copy"
android:layout_width="48dp"
android:layout_height="0dp"
android:layout_marginEnd="8dp"
android:background="?attr/selectableItemBackgroundBorderless"
android:src="@drawable/ic_file_copy"
android:tint="@color/colorPrimaryDark"
app:layout_constraintBottom_toBottomOf="@+id/material_password"
app:layout_constraintEnd_toStartOf="@id/visibleToggle"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/material_password_title"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginEnd="8dp"
android:textAppearance="@style/AppTheme.TextAppearance.ListTitle"
app:layout_constraintEnd_toStartOf="@+id/copy"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:text="Title" />
<TextView
android:id="@+id/material_password"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginEnd="8dp"
android:textAppearance="@style/AppTheme.TextAppearance.ListSubtitle"
android:visibility="visible"
app:layout_constraintEnd_toStartOf="@+id/copy"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/material_password_title"
tools:ignore="TextViewEdits"
tools:text="Subtitle" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -21,7 +21,7 @@
android:clickable="false"
android:focusable="false"
android:focusableInTouchMode="false"
android:textAppearance="@style/Text.Title"
android:textAppearance="@style/AppTheme.TextAppearance.ListTitle"
app:layout_constraintEnd_toStartOf="@id/material_preference_switch"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
@ -37,7 +37,7 @@
android:clickable="false"
android:focusable="false"
android:focusableInTouchMode="false"
android:textAppearance="@style/Text.SubTitle"
android:textAppearance="@style/AppTheme.TextAppearance.ListSubtitle"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@id/material_preference_switch"
app:layout_constraintStart_toStartOf="parent"

View File

@ -9,7 +9,7 @@
android:focusableInTouchMode="false"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:foreground="?attr/selectableItemBackground">
android:foreground="?attr/selectableItemBackgroundBorderless">
<ImageView
tools:src="@drawable/ic_language"
@ -20,9 +20,6 @@
android:layout_marginTop="8dp"
android:layout_marginBottom="8dp"
android:tint="@color/colorPrimaryDark"
android:clickable="false"
android:focusable="false"
android:focusableInTouchMode="false"
app:layout_constraintBottom_toBottomOf="@+id/material_preference_subtitle"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@+id/material_preference_title"
@ -36,10 +33,7 @@
android:layout_marginStart="16dp"
android:layout_marginTop="16dp"
android:layout_marginEnd="16dp"
android:textAppearance="@style/Text.Title"
android:clickable="false"
android:focusable="false"
android:focusableInTouchMode="false"
android:textAppearance="@style/AppTheme.TextAppearance.ListTitle"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/material_preference_src"
app:layout_constraintTop_toTopOf="parent" />
@ -52,10 +46,7 @@
android:layout_marginStart="16dp"
android:layout_marginEnd="16dp"
android:layout_marginBottom="16dp"
android:textAppearance="@style/Text.SubTitle"
android:clickable="false"
android:focusable="false"
android:focusableInTouchMode="false"
android:textAppearance="@style/AppTheme.TextAppearance.ListSubtitle"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/material_preference_src"

View File

@ -8,10 +8,9 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/white"
android:foreground="?attr/selectableItemBackground"
android:foreground="?attr/selectableItemBackgroundBorderless"
android:layout_marginBottom="1dp"
android:padding="8dp"
android:transitionName="root">
android:padding="8dp">
<ImageView
android:id="@+id/syncStatus"
@ -38,7 +37,7 @@
android:layout_marginTop="16dp"
android:layout_marginEnd="8dp"
android:layout_marginBottom="16dp"
android:textAppearance="@style/Text.Title"
android:textAppearance="@style/AppTheme.TextAppearance.ListTitle"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@+id/date"
app:layout_constraintStart_toEndOf="@+id/syncStatus"
@ -52,7 +51,7 @@
android:layout_marginTop="16dp"
android:layout_marginEnd="16dp"
android:layout_marginBottom="16dp"
android:textAppearance="@style/Text.SubTitle"
android:textAppearance="@style/TextAppearance.MaterialComponents.Caption"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"

View File

@ -1,48 +1,49 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.appcompat.widget.LinearLayoutCompat
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="16dp">
android:padding="16dp"
android:foreground="?attr/selectableItemBackground">
<LinearLayout
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<ImageView
android:id="@+id/stateView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/ic_error_outline"
android:tint="@color/black"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/title"
android:text="000"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:textAppearance="@style/Text.Title"
android:layout_gravity="center_vertical"
android:layout_marginEnd="8dp" />
<ImageView
android:id="@+id/stateView"
android:src="@drawable/ic_info_outline"
android:tint="@color/status_amber"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:contentDescription="Upload state" />
<ProgressBar
android:id="@+id/progressBar"
android:visibility="gone"
android:layout_width="24dp"
android:layout_height="24dp" />
</LinearLayout>
<ProgressBar
android:visibility="gone"
android:id="@+id/progressBar"
android:layout_width="24dp"
android:layout_height="24dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"/>
<TextView
android:id="@+id/title"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="2dp"
android:layout_marginEnd="16dp"
app:layout_constraintEnd_toStartOf="@+id/stateView"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:text="Title (upload action)" />
<TextView
android:id="@+id/error"
android:text="000"
android:textAppearance="@style/Text.SubTitle"
android:textColor="@color/status_red"
android:layout_marginEnd="24dp"
android:visibility="gone"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</androidx.appcompat.widget.LinearLayoutCompat>
android:id="@+id/error"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/title"
tools:text="Error" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -1,47 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="16dp"
android:foreground="?attr/selectableItemBackground">
<ImageView
android:id="@+id/stateView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/ic_error_outline"
android:tint="@color/black"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<ProgressBar
android:visibility="gone"
android:id="@+id/progressBar"
android:layout_width="24dp"
android:layout_height="24dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"/>
<TextView
android:id="@+id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="2dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:text="Title (upload action)" />
<TextView
android:visibility="gone"
android:id="@+id/error"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/title"
tools:text="Error" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -5,7 +5,7 @@
<attr name="subtitle" format="string"/>
<declare-styleable name="MaterialPreferenceText">
<attr name="pref_icon" format="integer"/>
<attr name="pref_icon" format="reference"/>
<attr name="title"/>
<attr name="subtitle"/>
</declare-styleable>
@ -15,6 +15,11 @@
<attr name="subtitle"/>
</declare-styleable>
<declare-styleable name="MaterialPasswordView">
<attr name="title"/>
<attr name="password"/>
</declare-styleable>
<declare-styleable name="UploadAction">
<attr name="description" format="string"/>
</declare-styleable>

View File

@ -12,4 +12,7 @@
<string name="qr_code">QR code</string>
<string name="sync">Synchronization</string>
<string name="no_syncs_hint">You have not synced any MISP instances yet</string>
<!-- TODO: Remove or change this placeholder text -->
<string name="hello_blank_fragment">Hello blank fragment</string>
</resources>

View File

@ -20,14 +20,14 @@
<item name="android:tint">#000</item>
</style>
<style name="Text"/>
<style name="AppTheme.TextAppearance"/>
<style name="Text.Title" >
<style name="AppTheme.TextAppearance.ListTitle" >
<item name="android:textColor">#de000000</item>
<item name="android:textSize">16dp</item>
</style>
<style name="Text.SubTitle" >
<style name="AppTheme.TextAppearance.ListSubtitle" >
<item name="android:textColor">#99000000</item>
<item name="android:textSize">14dp</item>
</style>