linked: redesign github resource creation, implement ouath flow (WIP)
This commit is contained in:
@@ -113,7 +113,17 @@
|
|||||||
<activity
|
<activity
|
||||||
android:name=".ui.linked.LinkedIdWizard"
|
android:name=".ui.linked.LinkedIdWizard"
|
||||||
android:configChanges="orientation|screenSize|keyboardHidden|keyboard"
|
android:configChanges="orientation|screenSize|keyboardHidden|keyboard"
|
||||||
android:label="@string/title_linked_create" />
|
android:launchMode="singleInstance"
|
||||||
|
android:label="@string/title_linked_create">
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.intent.action.VIEW" />
|
||||||
|
<category android:name="android.intent.category.DEFAULT" />
|
||||||
|
<category android:name="android.intent.category.BROWSABLE" />
|
||||||
|
<data
|
||||||
|
android:host="linked"
|
||||||
|
android:scheme="oauth-openkeychain" />
|
||||||
|
</intent-filter>
|
||||||
|
</activity>
|
||||||
<activity
|
<activity
|
||||||
android:name=".ui.QrCodeViewActivity"
|
android:name=".ui.QrCodeViewActivity"
|
||||||
android:label="@string/share_qr_code_dialog_title" />
|
android:label="@string/share_qr_code_dialog_title" />
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import android.graphics.PorterDuff;
|
|||||||
import android.os.AsyncTask;
|
import android.os.AsyncTask;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.Parcelable;
|
import android.os.Parcelable;
|
||||||
|
import android.support.annotation.NonNull;
|
||||||
import android.support.annotation.Nullable;
|
import android.support.annotation.Nullable;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
@@ -48,16 +49,19 @@ public abstract class LinkedIdCreateFinalFragment extends CryptoOperationFragmen
|
|||||||
|
|
||||||
protected abstract View newView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState);
|
protected abstract View newView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState);
|
||||||
|
|
||||||
@Override
|
@Override @NonNull
|
||||||
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
||||||
final View view = newView(inflater, container, savedInstanceState);
|
final View view = newView(inflater, container, savedInstanceState);
|
||||||
|
|
||||||
view.findViewById(R.id.next_button).setOnClickListener(new OnClickListener() {
|
View nextButton = view.findViewById(R.id.next_button);
|
||||||
@Override
|
if (nextButton != null) {
|
||||||
public void onClick(View v) {
|
nextButton.setOnClickListener(new OnClickListener() {
|
||||||
cryptoOperation();
|
@Override
|
||||||
}
|
public void onClick(View v) {
|
||||||
});
|
cryptoOperation();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
view.findViewById(R.id.back_button).setOnClickListener(new View.OnClickListener() {
|
view.findViewById(R.id.back_button).setOnClickListener(new View.OnClickListener() {
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -0,0 +1,246 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2014 Dominik Schürmann <dominik@dominikschuermann.de>
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.sufficientlysecure.keychain.ui.linked;
|
||||||
|
|
||||||
|
|
||||||
|
import java.io.BufferedInputStream;
|
||||||
|
import java.io.BufferedReader;
|
||||||
|
import java.io.BufferedWriter;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.InputStreamReader;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
import java.io.OutputStreamWriter;
|
||||||
|
import java.net.URL;
|
||||||
|
|
||||||
|
import android.os.AsyncTask;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.support.annotation.NonNull;
|
||||||
|
import android.support.v4.app.Fragment;
|
||||||
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.View.OnClickListener;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
import android.widget.EditText;
|
||||||
|
import android.widget.ViewAnimator;
|
||||||
|
|
||||||
|
import javax.net.ssl.HttpsURLConnection;
|
||||||
|
import org.json.JSONException;
|
||||||
|
import org.json.JSONObject;
|
||||||
|
import org.sufficientlysecure.keychain.BuildConfig;
|
||||||
|
import org.sufficientlysecure.keychain.Constants;
|
||||||
|
import org.sufficientlysecure.keychain.R;
|
||||||
|
import org.sufficientlysecure.keychain.ui.widget.StatusIndicator;
|
||||||
|
import org.sufficientlysecure.keychain.util.Log;
|
||||||
|
|
||||||
|
|
||||||
|
public class LinkedIdCreateGithubFragment extends Fragment {
|
||||||
|
|
||||||
|
ViewAnimator mProceedContainer;
|
||||||
|
EditText mGithubUsername, mGithubPassword;
|
||||||
|
|
||||||
|
StatusIndicator mStatus1, mStatus2, mStatus3;
|
||||||
|
|
||||||
|
public static LinkedIdCreateGithubFragment newInstance() {
|
||||||
|
return new LinkedIdCreateGithubFragment();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override @NonNull
|
||||||
|
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
||||||
|
View view = inflater.inflate(R.layout.linked_create_github_fragment, container, false);
|
||||||
|
|
||||||
|
mProceedContainer = (ViewAnimator) view.findViewById(R.id.proceed_container);
|
||||||
|
|
||||||
|
mGithubUsername = (EditText) view.findViewById(R.id.username);
|
||||||
|
mGithubPassword = (EditText) view.findViewById(R.id.password);
|
||||||
|
|
||||||
|
mStatus1 = (StatusIndicator) view.findViewById(R.id.linked_status_step1);
|
||||||
|
mStatus2 = (StatusIndicator) view.findViewById(R.id.linked_status_step2);
|
||||||
|
mStatus3 = (StatusIndicator) view.findViewById(R.id.linked_status_step3);
|
||||||
|
|
||||||
|
view.findViewById(R.id.button_send).setOnClickListener(new OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
step1GetOAuthToken();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return view;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onResume() {
|
||||||
|
super.onResume();
|
||||||
|
|
||||||
|
LinkedIdWizard wizard = (LinkedIdWizard) getActivity();
|
||||||
|
final String oAuthCode = wizard.oAuthGetCode();
|
||||||
|
final String oAuthState = wizard.oAuthGetState();
|
||||||
|
if (oAuthCode == null) {
|
||||||
|
Log.d(Constants.TAG, "no code");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Log.d(Constants.TAG, "got code: " + oAuthCode);
|
||||||
|
|
||||||
|
new AsyncTask<Void,Void,JSONObject>() {
|
||||||
|
@Override
|
||||||
|
protected JSONObject doInBackground(Void... dummy) {
|
||||||
|
try {
|
||||||
|
|
||||||
|
JSONObject params = new JSONObject();
|
||||||
|
params.put("client_id", "7a011b66275f244d3f21");
|
||||||
|
params.put("client_secret", "eaced8a6655719d8c6848396de97b3f5d7a89fec");
|
||||||
|
params.put("code", oAuthCode);
|
||||||
|
params.put("state", oAuthState);
|
||||||
|
|
||||||
|
return jsonHttpRequest("https://github.com/login/oauth/access_token", params, null);
|
||||||
|
|
||||||
|
} catch (IOException e) {
|
||||||
|
Log.e(Constants.TAG, "error in request", e);
|
||||||
|
} catch (JSONException e) {
|
||||||
|
throw new AssertionError("json error, this is a bug!");
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onPostExecute(JSONObject result) {
|
||||||
|
super.onPostExecute(result);
|
||||||
|
|
||||||
|
Log.d(Constants.TAG, "response: " + result);
|
||||||
|
|
||||||
|
if (result == null || !result.has("access_token")) {
|
||||||
|
mStatus1.setDisplayedChild(3);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
mStatus1.setDisplayedChild(2);
|
||||||
|
step2PostGist(result.optString("access_token"));
|
||||||
|
|
||||||
|
}
|
||||||
|
}.execute();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private void step1GetOAuthToken() {
|
||||||
|
|
||||||
|
mStatus1.setDisplayedChild(1);
|
||||||
|
mStatus2.setDisplayedChild(0);
|
||||||
|
mStatus3.setDisplayedChild(0);
|
||||||
|
|
||||||
|
mProceedContainer.setDisplayedChild(1);
|
||||||
|
|
||||||
|
LinkedIdWizard wizard = (LinkedIdWizard) getActivity();
|
||||||
|
wizard.oAuthRequest("github.com/login/oauth/authorize", "7a011b66275f244d3f21", "gist");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private void step2PostGist(final String accessToken) {
|
||||||
|
|
||||||
|
mStatus2.setDisplayedChild(1);
|
||||||
|
|
||||||
|
new AsyncTask<Void,Void,JSONObject>() {
|
||||||
|
@Override
|
||||||
|
protected JSONObject doInBackground(Void... dummy) {
|
||||||
|
try {
|
||||||
|
|
||||||
|
JSONObject file = new JSONObject();
|
||||||
|
file.put("content", "hello!");
|
||||||
|
|
||||||
|
JSONObject files = new JSONObject();
|
||||||
|
files.put("file1.txt", file);
|
||||||
|
|
||||||
|
JSONObject params = new JSONObject();
|
||||||
|
params.put("public", true);
|
||||||
|
params.put("description", "OpenKeychain API Tests");
|
||||||
|
params.put("files", files);
|
||||||
|
|
||||||
|
return jsonHttpRequest("https://api.github.com/gists", params, accessToken);
|
||||||
|
|
||||||
|
} catch (IOException e) {
|
||||||
|
Log.e(Constants.TAG, "error in request", e);
|
||||||
|
} catch (JSONException e) {
|
||||||
|
throw new AssertionError("json error, this is a bug!");
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onPostExecute(JSONObject result) {
|
||||||
|
super.onPostExecute(result);
|
||||||
|
|
||||||
|
Log.d(Constants.TAG, "response: " + result);
|
||||||
|
|
||||||
|
if (result == null) {
|
||||||
|
mStatus2.setDisplayedChild(3);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
mStatus2.setDisplayedChild(2);
|
||||||
|
}
|
||||||
|
}.execute();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private static JSONObject jsonHttpRequest(String url, JSONObject params, String accessToken)
|
||||||
|
throws IOException {
|
||||||
|
|
||||||
|
HttpsURLConnection nection = (HttpsURLConnection) new URL(url).openConnection();
|
||||||
|
nection.setDoInput(true);
|
||||||
|
nection.setDoOutput(true);
|
||||||
|
nection.setRequestProperty("Content-Type", "application/json");
|
||||||
|
nection.setRequestProperty("Accept", "application/json");
|
||||||
|
nection.setRequestProperty("User-Agent", "OpenKeychain " + BuildConfig.VERSION_NAME);
|
||||||
|
if (accessToken != null) {
|
||||||
|
nection.setRequestProperty("Authorization", "token " + accessToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
OutputStream os = nection.getOutputStream();
|
||||||
|
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(os, "UTF-8"));
|
||||||
|
writer.write(params.toString());
|
||||||
|
writer.flush();
|
||||||
|
writer.close();
|
||||||
|
os.close();
|
||||||
|
|
||||||
|
try {
|
||||||
|
|
||||||
|
nection.connect();
|
||||||
|
InputStream in = new BufferedInputStream(nection.getInputStream());
|
||||||
|
BufferedReader reader = new BufferedReader(new InputStreamReader(in));
|
||||||
|
StringBuilder response = new StringBuilder();
|
||||||
|
while (true) {
|
||||||
|
String line = reader.readLine();
|
||||||
|
if (line == null) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
response.append(line);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
return new JSONObject(response.toString());
|
||||||
|
} catch (JSONException e) {
|
||||||
|
throw new IOException(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
} finally {
|
||||||
|
nection.disconnect();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -84,8 +84,8 @@ public class LinkedIdSelectFragment extends Fragment {
|
|||||||
.setOnClickListener(new View.OnClickListener() {
|
.setOnClickListener(new View.OnClickListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onClick(View v) {
|
public void onClick(View v) {
|
||||||
LinkedIdCreateGithubStep1Fragment frag =
|
LinkedIdCreateGithubFragment frag =
|
||||||
LinkedIdCreateGithubStep1Fragment.newInstance();
|
LinkedIdCreateGithubFragment.newInstance();
|
||||||
|
|
||||||
mLinkedIdWizard.loadFragment(null, frag, LinkedIdWizard.FRAG_ACTION_TO_RIGHT);
|
mLinkedIdWizard.loadFragment(null, frag, LinkedIdWizard.FRAG_ACTION_TO_RIGHT);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,7 +17,10 @@
|
|||||||
|
|
||||||
package org.sufficientlysecure.keychain.ui.linked;
|
package org.sufficientlysecure.keychain.ui.linked;
|
||||||
|
|
||||||
|
import java.util.Random;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.support.v4.app.Fragment;
|
import android.support.v4.app.Fragment;
|
||||||
@@ -25,6 +28,7 @@ import android.support.v4.app.FragmentTransaction;
|
|||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.inputmethod.InputMethodManager;
|
import android.view.inputmethod.InputMethodManager;
|
||||||
|
|
||||||
|
import org.spongycastle.util.encoders.Hex;
|
||||||
import org.sufficientlysecure.keychain.Constants;
|
import org.sufficientlysecure.keychain.Constants;
|
||||||
import org.sufficientlysecure.keychain.R;
|
import org.sufficientlysecure.keychain.R;
|
||||||
import org.sufficientlysecure.keychain.pgp.exception.PgpKeyNotFoundException;
|
import org.sufficientlysecure.keychain.pgp.exception.PgpKeyNotFoundException;
|
||||||
@@ -32,6 +36,8 @@ import org.sufficientlysecure.keychain.provider.CachedPublicKeyRing;
|
|||||||
import org.sufficientlysecure.keychain.provider.KeychainContract;
|
import org.sufficientlysecure.keychain.provider.KeychainContract;
|
||||||
import org.sufficientlysecure.keychain.provider.ProviderHelper;
|
import org.sufficientlysecure.keychain.provider.ProviderHelper;
|
||||||
import org.sufficientlysecure.keychain.ui.base.BaseActivity;
|
import org.sufficientlysecure.keychain.ui.base.BaseActivity;
|
||||||
|
import org.sufficientlysecure.keychain.ui.util.Notify;
|
||||||
|
import org.sufficientlysecure.keychain.ui.util.Notify.Style;
|
||||||
import org.sufficientlysecure.keychain.util.Log;
|
import org.sufficientlysecure.keychain.util.Log;
|
||||||
|
|
||||||
public class LinkedIdWizard extends BaseActivity {
|
public class LinkedIdWizard extends BaseActivity {
|
||||||
@@ -125,4 +131,55 @@ public class LinkedIdWizard extends BaseActivity {
|
|||||||
inputManager.hideSoftInputFromWindow(v.getWindowToken(), 0);
|
inputManager.hideSoftInputFromWindow(v.getWindowToken(), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private String mOAuthCode, mOAuthState;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onNewIntent(Intent intent) {
|
||||||
|
super.onNewIntent(intent);
|
||||||
|
|
||||||
|
Uri uri = intent.getData();
|
||||||
|
if (uri != null) {
|
||||||
|
Log.d(Constants.TAG, "received oauth uri: " + uri);
|
||||||
|
String state = uri.getQueryParameter("state");
|
||||||
|
if (!mOAuthState.equalsIgnoreCase(state)) {
|
||||||
|
Notify.create(this, "Authentication Error!", Style.ERROR).show();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
mOAuthCode = uri.getQueryParameter("code");
|
||||||
|
} else {
|
||||||
|
Log.d(Constants.TAG, "received oauth uri: null");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public String oAuthGetCode() {
|
||||||
|
try {
|
||||||
|
return mOAuthCode;
|
||||||
|
} finally {
|
||||||
|
mOAuthCode = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public String oAuthGetState() {
|
||||||
|
return mOAuthState;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void oAuthRequest(String hostAndPath, String clientId, String scope) {
|
||||||
|
|
||||||
|
byte[] buf = new byte[16];
|
||||||
|
new Random().nextBytes(buf);
|
||||||
|
mOAuthState = new String(Hex.encode(buf));
|
||||||
|
|
||||||
|
Intent intent = new Intent(
|
||||||
|
Intent.ACTION_VIEW,
|
||||||
|
Uri.parse("https://" + hostAndPath +
|
||||||
|
"?client_id=" + clientId +
|
||||||
|
"&scope=" + scope +
|
||||||
|
"&redirect_uri=oauth-openkeychain://linked/" +
|
||||||
|
"&state=" + mOAuthState));
|
||||||
|
|
||||||
|
startActivity(intent);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,172 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
xmlns:custom="http://schemas.android.com/apk/res-auto">
|
||||||
|
|
||||||
|
<ScrollView
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:fillViewport="false"
|
||||||
|
android:layout_above="@+id/create_key_button_divider">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:padding="16dp"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center_horizontal"
|
||||||
|
android:layout_margin="8dp"
|
||||||
|
android:src="@drawable/linked_github" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="8dp"
|
||||||
|
android:layout_marginBottom="16dp"
|
||||||
|
android:text="This login data will be used to post a gist, verifying this account and key belongs to you!"
|
||||||
|
style="?android:textAppearanceSmall"/>
|
||||||
|
|
||||||
|
<org.sufficientlysecure.keychain.ui.widget.ToolableViewAnimator
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:id="@+id/proceed_container"
|
||||||
|
custom:initialView="1">
|
||||||
|
|
||||||
|
<Button
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center_horizontal"
|
||||||
|
android:layout_marginTop="16dp"
|
||||||
|
android:layout_marginBottom="16dp"
|
||||||
|
style="?android:buttonBarButtonStyle"
|
||||||
|
android:drawableLeft="@drawable/ic_mode_edit_grey_24dp"
|
||||||
|
android:drawableStart="@drawable/ic_mode_edit_grey_24dp"
|
||||||
|
android:drawablePadding="12dp"
|
||||||
|
android:text="Post Gist & Link Key"
|
||||||
|
android:id="@+id/button_send"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content">
|
||||||
|
|
||||||
|
<org.sufficientlysecure.keychain.ui.widget.StatusIndicator
|
||||||
|
android:layout_width="24dp"
|
||||||
|
android:layout_height="24dp"
|
||||||
|
android:id="@+id/linked_status_step1"
|
||||||
|
android:layout_margin="4dp">
|
||||||
|
</org.sufficientlysecure.keychain.ui.widget.StatusIndicator>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center_vertical"
|
||||||
|
android:text="Login at GitHub…"
|
||||||
|
style="?android:textAppearanceMedium"
|
||||||
|
/>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content">
|
||||||
|
|
||||||
|
<org.sufficientlysecure.keychain.ui.widget.StatusIndicator
|
||||||
|
android:layout_width="24dp"
|
||||||
|
android:layout_height="24dp"
|
||||||
|
android:id="@+id/linked_status_step2"
|
||||||
|
android:layout_margin="4dp">
|
||||||
|
</org.sufficientlysecure.keychain.ui.widget.StatusIndicator>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center_vertical"
|
||||||
|
android:text="Post Gist…"
|
||||||
|
style="?android:textAppearanceMedium"
|
||||||
|
/>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content">
|
||||||
|
|
||||||
|
<org.sufficientlysecure.keychain.ui.widget.StatusIndicator
|
||||||
|
android:layout_width="24dp"
|
||||||
|
android:layout_height="24dp"
|
||||||
|
android:id="@+id/linked_status_step3"
|
||||||
|
android:layout_margin="4dp">
|
||||||
|
</org.sufficientlysecure.keychain.ui.widget.StatusIndicator>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center_vertical"
|
||||||
|
android:text="Update Key…"
|
||||||
|
style="?android:textAppearanceMedium"
|
||||||
|
/>
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</org.sufficientlysecure.keychain.ui.widget.ToolableViewAnimator>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</ScrollView>
|
||||||
|
|
||||||
|
<View
|
||||||
|
android:id="@+id/create_key_button_divider"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="1dip"
|
||||||
|
android:layout_marginLeft="16dp"
|
||||||
|
android:layout_marginRight="16dp"
|
||||||
|
android:background="?android:attr/listDivider"
|
||||||
|
android:layout_alignTop="@+id/create_key_buttons"
|
||||||
|
android:layout_alignParentLeft="true"
|
||||||
|
android:layout_alignParentStart="true" />
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:layout_alignParentBottom="true"
|
||||||
|
android:layout_alignParentLeft="true"
|
||||||
|
android:layout_alignParentStart="true"
|
||||||
|
android:layout_marginLeft="16dp"
|
||||||
|
android:layout_marginRight="16dp"
|
||||||
|
android:id="@+id/create_key_buttons">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/back_button"
|
||||||
|
android:paddingLeft="8dp"
|
||||||
|
android:paddingRight="8dp"
|
||||||
|
android:textAppearance="?android:attr/textAppearanceMedium"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:text="@string/btn_cancel"
|
||||||
|
android:minHeight="?android:attr/listPreferredItemHeight"
|
||||||
|
android:textAllCaps="true"
|
||||||
|
style="?android:attr/borderlessButtonStyle"
|
||||||
|
android:drawableLeft="@drawable/ic_chevron_left_grey_24dp"
|
||||||
|
android:drawablePadding="8dp"
|
||||||
|
android:gravity="center_vertical"
|
||||||
|
android:clickable="true"
|
||||||
|
android:layout_gravity="center_vertical" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</RelativeLayout>
|
||||||
@@ -4,8 +4,7 @@
|
|||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginTop="8dp"
|
tools:showIn="@layout/linked_create_github_fragment_step2">
|
||||||
tools:showIn="@layout/linked_create_https_fragment_step2">
|
|
||||||
|
|
||||||
<ViewAnimator
|
<ViewAnimator
|
||||||
android:id="@+id/verify_progress"
|
android:id="@+id/verify_progress"
|
||||||
|
|||||||
@@ -82,6 +82,7 @@
|
|||||||
<string name="btn_export_to_server">"Upload To Keyserver"</string>
|
<string name="btn_export_to_server">"Upload To Keyserver"</string>
|
||||||
<string name="btn_next">"Next"</string>
|
<string name="btn_next">"Next"</string>
|
||||||
<string name="btn_back">"Back"</string>
|
<string name="btn_back">"Back"</string>
|
||||||
|
<string name="btn_cancel">"Cancel"</string>
|
||||||
<string name="btn_no">"No"</string>
|
<string name="btn_no">"No"</string>
|
||||||
<string name="btn_match">"Fingerprints match"</string>
|
<string name="btn_match">"Fingerprints match"</string>
|
||||||
<string name="btn_share_encrypted_signed">"Encrypt/sign and share text"</string>
|
<string name="btn_share_encrypted_signed">"Encrypt/sign and share text"</string>
|
||||||
|
|||||||
Reference in New Issue
Block a user