mirror of
https://github.com/moparisthebest/open-keychain
synced 2024-12-26 00:48:51 -05:00
More experimental work on api accounts
This commit is contained in:
parent
031beed680
commit
cff35ca842
@ -95,8 +95,6 @@ public class KeychainContract {
|
||||
public static final String BASE_API_APPS = "api_apps";
|
||||
public static final String PATH_ACCOUNTS = "accounts";
|
||||
|
||||
public static final String PATH_BY_PACKAGE_NAME = "package_name";
|
||||
|
||||
public static class KeyRings implements KeyRingsColumns, BaseColumns {
|
||||
public static final Uri CONTENT_URI = BASE_CONTENT_URI_INTERNAL.buildUpon()
|
||||
.appendPath(BASE_KEY_RINGS).build();
|
||||
@ -272,13 +270,12 @@ public class KeychainContract {
|
||||
*/
|
||||
public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/vnd.thialfihar.apg.api.apps";
|
||||
|
||||
public static Uri buildIdUri(String rowId) {
|
||||
return CONTENT_URI.buildUpon().appendPath(rowId).build();
|
||||
}
|
||||
// public static Uri buildIdUri(String rowId) {
|
||||
// return CONTENT_URI.buildUpon().appendPath(rowId).build();
|
||||
// }
|
||||
|
||||
public static Uri buildByPackageNameUri(String packageName) {
|
||||
return CONTENT_URI.buildUpon().appendPath(PATH_BY_PACKAGE_NAME)
|
||||
.appendEncodedPath(packageName).build();
|
||||
return CONTENT_URI.buildUpon().appendEncodedPath(packageName).build();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -80,10 +80,8 @@ public class KeychainProvider extends ContentProvider {
|
||||
private static final int SECRET_KEY_RING_USER_ID_BY_ROW_ID = 222;
|
||||
|
||||
private static final int API_APPS = 301;
|
||||
private static final int API_APPS_BY_ROW_ID = 302;
|
||||
private static final int API_APPS_BY_PACKAGE_NAME = 303;
|
||||
private static final int API_ACCOUNTS = 304;
|
||||
private static final int API_ACCOUNTS_BY_ROW_ID = 305;
|
||||
private static final int API_ACCOUNTS_BY_ACCOUNT_NAME = 306;
|
||||
|
||||
private static final int UNIFIED_KEY_RING = 401;
|
||||
@ -241,19 +239,22 @@ public class KeychainProvider extends ContentProvider {
|
||||
|
||||
/**
|
||||
* API apps
|
||||
*
|
||||
* <pre>
|
||||
* api_apps
|
||||
* api_apps/_
|
||||
*
|
||||
* api_apps/_/accounts
|
||||
* api_apps/_/accounts/_
|
||||
* </pre>
|
||||
*/
|
||||
matcher.addURI(authority, KeychainContract.BASE_API_APPS, API_APPS);
|
||||
matcher.addURI(authority, KeychainContract.BASE_API_APPS + "/#", API_APPS_BY_ROW_ID);
|
||||
matcher.addURI(authority, KeychainContract.BASE_API_APPS + "/"
|
||||
+ KeychainContract.PATH_BY_PACKAGE_NAME + "/*", API_APPS_BY_PACKAGE_NAME);
|
||||
matcher.addURI(authority, KeychainContract.BASE_API_APPS + "/*", API_APPS_BY_PACKAGE_NAME);
|
||||
|
||||
matcher.addURI(authority, KeychainContract.BASE_API_APPS + "/"
|
||||
matcher.addURI(authority, KeychainContract.BASE_API_APPS + "/*/"
|
||||
+ KeychainContract.PATH_ACCOUNTS, API_ACCOUNTS);
|
||||
matcher.addURI(authority, KeychainContract.BASE_API_APPS + "/"
|
||||
+ KeychainContract.PATH_ACCOUNTS + "/#", API_ACCOUNTS_BY_ROW_ID);
|
||||
matcher.addURI(authority, KeychainContract.BASE_API_APPS + "/"
|
||||
+ KeychainContract.PATH_ACCOUNTS + "/"
|
||||
+ KeychainContract.PATH_BY_PACKAGE_NAME + "/*", API_ACCOUNTS_BY_ACCOUNT_NAME);
|
||||
matcher.addURI(authority, KeychainContract.BASE_API_APPS + "/*/"
|
||||
+ KeychainContract.PATH_ACCOUNTS + "/*", API_ACCOUNTS_BY_ACCOUNT_NAME);
|
||||
|
||||
/**
|
||||
* data stream
|
||||
@ -322,14 +323,12 @@ public class KeychainProvider extends ContentProvider {
|
||||
case API_APPS:
|
||||
return ApiApps.CONTENT_TYPE;
|
||||
|
||||
case API_APPS_BY_ROW_ID:
|
||||
case API_APPS_BY_PACKAGE_NAME:
|
||||
return ApiApps.CONTENT_ITEM_TYPE;
|
||||
|
||||
case API_ACCOUNTS:
|
||||
return ApiAccounts.CONTENT_TYPE;
|
||||
|
||||
case API_ACCOUNTS_BY_ROW_ID:
|
||||
case API_ACCOUNTS_BY_ACCOUNT_NAME:
|
||||
return ApiAccounts.CONTENT_ITEM_TYPE;
|
||||
|
||||
@ -679,13 +678,6 @@ public class KeychainProvider extends ContentProvider {
|
||||
case API_APPS:
|
||||
qb.setTables(Tables.API_APPS);
|
||||
|
||||
break;
|
||||
case API_APPS_BY_ROW_ID:
|
||||
qb.setTables(Tables.API_APPS);
|
||||
|
||||
qb.appendWhere(BaseColumns._ID + " = ");
|
||||
qb.appendWhereEscapeString(uri.getLastPathSegment());
|
||||
|
||||
break;
|
||||
case API_APPS_BY_PACKAGE_NAME:
|
||||
qb.setTables(Tables.API_APPS);
|
||||
@ -696,17 +688,6 @@ public class KeychainProvider extends ContentProvider {
|
||||
case API_ACCOUNTS:
|
||||
qb.setTables(Tables.API_ACCOUNTS);
|
||||
|
||||
break;
|
||||
case API_ACCOUNTS_BY_ROW_ID:
|
||||
qb.setTables(Tables.API_ACCOUNTS + " INNER JOIN " + Tables.API_APPS + " ON " + "("
|
||||
+ Tables.API_APPS + "." + ApiApps.PACKAGE_NAME + " = " + Tables.API_ACCOUNTS + "."
|
||||
+ ApiAccounts.PACKAGE_NAME_FK + " )");
|
||||
qb.appendWhere(Tables.API_APPS + "." + BaseColumns._ID + " = ");
|
||||
qb.appendWhereEscapeString(uri.getPathSegments().get(2));
|
||||
|
||||
qb.appendWhere(" AND " + Tables.API_ACCOUNTS + "." + BaseColumns._ID + " = ");
|
||||
qb.appendWhereEscapeString(uri.getLastPathSegment());
|
||||
|
||||
break;
|
||||
case API_ACCOUNTS_BY_ACCOUNT_NAME:
|
||||
qb.setTables(Tables.API_ACCOUNTS + " INNER JOIN " + Tables.API_APPS + " ON " + "("
|
||||
@ -812,7 +793,7 @@ public class KeychainProvider extends ContentProvider {
|
||||
break;
|
||||
case API_APPS:
|
||||
rowId = db.insertOrThrow(Tables.API_APPS, null, values);
|
||||
rowUri = ApiApps.buildIdUri(Long.toString(rowId));
|
||||
// rowUri = ApiApps.buildIdUri(Long.toString(rowId));
|
||||
|
||||
break;
|
||||
case API_ACCOUNTS:
|
||||
@ -878,18 +859,10 @@ public class KeychainProvider extends ContentProvider {
|
||||
count = db.delete(Tables.KEYS, buildDefaultUserIdsSelection(uri, selection),
|
||||
selectionArgs);
|
||||
break;
|
||||
case API_APPS_BY_ROW_ID:
|
||||
count = db.delete(Tables.API_APPS, buildDefaultApiAppsSelection(uri, false, selection),
|
||||
selectionArgs);
|
||||
break;
|
||||
case API_APPS_BY_PACKAGE_NAME:
|
||||
count = db.delete(Tables.API_APPS, buildDefaultApiAppsSelection(uri, true, selection),
|
||||
selectionArgs);
|
||||
break;
|
||||
case API_ACCOUNTS_BY_ROW_ID:
|
||||
count = db.delete(Tables.API_ACCOUNTS, buildDefaultApiAccountsSelection(uri, false, selection),
|
||||
selectionArgs);
|
||||
break;
|
||||
case API_ACCOUNTS_BY_ACCOUNT_NAME:
|
||||
count = db.delete(Tables.API_ACCOUNTS, buildDefaultApiAccountsSelection(uri, true, selection),
|
||||
selectionArgs);
|
||||
@ -956,18 +929,10 @@ public class KeychainProvider extends ContentProvider {
|
||||
count = db.update(Tables.USER_IDS, values,
|
||||
buildDefaultUserIdsSelection(uri, selection), selectionArgs);
|
||||
break;
|
||||
case API_APPS_BY_ROW_ID:
|
||||
count = db.update(Tables.API_APPS, values,
|
||||
buildDefaultApiAppsSelection(uri, false, selection), selectionArgs);
|
||||
break;
|
||||
case API_APPS_BY_PACKAGE_NAME:
|
||||
count = db.update(Tables.API_APPS, values,
|
||||
buildDefaultApiAppsSelection(uri, true, selection), selectionArgs);
|
||||
break;
|
||||
case API_ACCOUNTS_BY_ROW_ID:
|
||||
count = db.update(Tables.API_ACCOUNTS, values,
|
||||
buildDefaultApiAccountsSelection(uri, false, selection), selectionArgs);
|
||||
break;
|
||||
case API_ACCOUNTS_BY_ACCOUNT_NAME:
|
||||
count = db.update(Tables.API_ACCOUNTS, values,
|
||||
buildDefaultApiAccountsSelection(uri, true, selection), selectionArgs);
|
||||
|
@ -19,10 +19,7 @@ package org.sufficientlysecure.keychain.remote.ui;
|
||||
|
||||
import android.annotation.TargetApi;
|
||||
import android.content.ContentUris;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.database.Cursor;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
@ -31,15 +28,10 @@ import android.support.v4.app.ListFragment;
|
||||
import android.support.v4.app.LoaderManager;
|
||||
import android.support.v4.content.CursorLoader;
|
||||
import android.support.v4.content.Loader;
|
||||
import android.support.v4.widget.CursorAdapter;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.AdapterView;
|
||||
import android.widget.AdapterView.OnItemClickListener;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.SimpleCursorAdapter;
|
||||
import android.widget.TextView;
|
||||
|
||||
import org.sufficientlysecure.keychain.R;
|
||||
import org.sufficientlysecure.keychain.provider.KeychainContract;
|
||||
@ -50,36 +42,46 @@ import org.sufficientlysecure.keychain.provider.KeychainContract.ApiApps;
|
||||
public class AccountsListFragment extends ListFragment implements
|
||||
LoaderManager.LoaderCallbacks<Cursor> {
|
||||
|
||||
private static final String ARG_DATA_URI = "uri";
|
||||
|
||||
// This is the Adapter being used to display the list's data.
|
||||
SimpleCursorAdapter mAdapter;
|
||||
|
||||
private String mPackageName;
|
||||
private Uri mDataUri;
|
||||
|
||||
public String getPackageName() {
|
||||
return mPackageName;
|
||||
}
|
||||
/**
|
||||
* Creates new instance of this fragment
|
||||
*/
|
||||
public static AccountsListFragment newInstance(Uri dataUri) {
|
||||
AccountsListFragment frag = new AccountsListFragment();
|
||||
|
||||
public void setPackageName(String packageName) {
|
||||
this.mPackageName = packageName;
|
||||
Bundle args = new Bundle();
|
||||
args.putParcelable(ARG_DATA_URI, dataUri);
|
||||
|
||||
frag.setArguments(args);
|
||||
|
||||
return frag;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivityCreated(Bundle savedInstanceState) {
|
||||
super.onActivityCreated(savedInstanceState);
|
||||
|
||||
mDataUri = getArguments().getParcelable(ARG_DATA_URI);
|
||||
|
||||
getListView().setOnItemClickListener(new OnItemClickListener() {
|
||||
@Override
|
||||
public void onItemClick(AdapterView<?> adapterView, View view, int position, long id) {
|
||||
// edit app settings
|
||||
Intent intent = new Intent(getActivity(), AppSettingsActivity.class);
|
||||
intent.setData(ContentUris.withAppendedId(ApiApps.CONTENT_URI, id));
|
||||
startActivity(intent);
|
||||
// // edit app settings
|
||||
// Intent intent = new Intent(getActivity(), AppSettingsActivity.class);
|
||||
// intent.setData(ContentUris.withAppendedId(ApiApps.CONTENT_URI, id));
|
||||
// startActivity(intent);
|
||||
}
|
||||
});
|
||||
|
||||
// Give some text to display if there is no data. In a real
|
||||
// application this would come from a resource.
|
||||
setEmptyText(getString(R.string.api_no_apps));
|
||||
setEmptyText(getString(R.string.api_settings_accounts_empty));
|
||||
|
||||
// We have a menu item to show in action bar.
|
||||
setHasOptionsMenu(true);
|
||||
@ -108,11 +110,11 @@ public class AccountsListFragment extends ListFragment implements
|
||||
// sample only has one Loader, so we don't care about the ID.
|
||||
// First, pick the base URI to use depending on whether we are
|
||||
// currently filtering.
|
||||
Uri baseUri = KeychainContract.ApiAccounts.buildBaseUri(mPackageName);
|
||||
// Uri baseUri = KeychainContract.ApiAccounts.buildBaseUri(mPackageName);
|
||||
|
||||
// Now create and return a CursorLoader that will take care of
|
||||
// creating a Cursor for the data being displayed.
|
||||
return new CursorLoader(getActivity(), baseUri, PROJECTION, null, null,
|
||||
return new CursorLoader(getActivity(), mDataUri, PROJECTION, null, null,
|
||||
KeychainContract.ApiAccounts.ACCOUNT_NAME + " COLLATE LOCALIZED ASC");
|
||||
}
|
||||
|
||||
|
@ -24,9 +24,11 @@ import android.support.v7.app.ActionBarActivity;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
|
||||
import org.sufficientlysecure.keychain.Constants;
|
||||
import org.sufficientlysecure.keychain.R;
|
||||
import org.sufficientlysecure.keychain.helper.ActionBarHelper;
|
||||
import org.sufficientlysecure.keychain.provider.KeychainContract;
|
||||
import org.sufficientlysecure.keychain.provider.ProviderHelper;
|
||||
import org.sufficientlysecure.keychain.remote.AppSettings;
|
||||
import org.sufficientlysecure.keychain.util.Log;
|
||||
@ -35,6 +37,7 @@ public class AppSettingsActivity extends ActionBarActivity {
|
||||
private Uri mAppUri;
|
||||
|
||||
private AppSettingsFragment mSettingsFragment;
|
||||
private AccountsListFragment mAccountsListFragment;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
@ -64,7 +67,7 @@ public class AppSettingsActivity extends ActionBarActivity {
|
||||
return;
|
||||
} else {
|
||||
Log.d(Constants.TAG, "uri: " + mAppUri);
|
||||
loadData(mAppUri);
|
||||
loadData(savedInstanceState, mAppUri);
|
||||
}
|
||||
}
|
||||
|
||||
@ -88,9 +91,34 @@ public class AppSettingsActivity extends ActionBarActivity {
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
|
||||
private void loadData(Uri appUri) {
|
||||
private void loadData(Bundle savedInstanceState, Uri appUri) {
|
||||
// TODO: load this also like other fragment with newInstance arguments?
|
||||
AppSettings settings = ProviderHelper.getApiAppSettings(this, appUri);
|
||||
mSettingsFragment.setAppSettings(settings);
|
||||
|
||||
Uri accountsUri = appUri.buildUpon().appendPath(KeychainContract.PATH_ACCOUNTS).build();
|
||||
Log.d(Constants.TAG, "accountsUri: " + accountsUri);
|
||||
startListFragment(savedInstanceState, accountsUri);
|
||||
}
|
||||
|
||||
private void startListFragment(Bundle savedInstanceState, Uri dataUri) {
|
||||
// However, if we're being restored from a previous state,
|
||||
// then we don't need to do anything and should return or else
|
||||
// we could end up with overlapping fragments.
|
||||
if (savedInstanceState != null) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Create an instance of the fragment
|
||||
mAccountsListFragment = AccountsListFragment.newInstance(dataUri);
|
||||
|
||||
// Add the fragment to the 'fragment_container' FrameLayout
|
||||
// NOTE: We use commitAllowingStateLoss() to prevent weird crashes!
|
||||
getSupportFragmentManager().beginTransaction()
|
||||
.replace(R.id.api_accounts_list_fragment, mAccountsListFragment)
|
||||
.commitAllowingStateLoss();
|
||||
// do it immediately!
|
||||
getSupportFragmentManager().executePendingTransactions();
|
||||
}
|
||||
|
||||
private void revokeAccess() {
|
||||
|
@ -17,7 +17,6 @@
|
||||
|
||||
package org.sufficientlysecure.keychain.remote.ui;
|
||||
|
||||
import android.content.ContentUris;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
@ -38,9 +37,11 @@ import android.widget.AdapterView.OnItemClickListener;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import org.sufficientlysecure.keychain.Constants;
|
||||
import org.sufficientlysecure.keychain.R;
|
||||
import org.sufficientlysecure.keychain.provider.KeychainContract;
|
||||
import org.sufficientlysecure.keychain.provider.KeychainContract.ApiApps;
|
||||
import org.sufficientlysecure.keychain.util.Log;
|
||||
|
||||
public class AppsListFragment extends ListFragment implements
|
||||
LoaderManager.LoaderCallbacks<Cursor> {
|
||||
@ -55,9 +56,10 @@ public class AppsListFragment extends ListFragment implements
|
||||
getListView().setOnItemClickListener(new OnItemClickListener() {
|
||||
@Override
|
||||
public void onItemClick(AdapterView<?> adapterView, View view, int position, long id) {
|
||||
String selectedPackageName = mAdapter.getItemPackageName(position);
|
||||
// edit app settings
|
||||
Intent intent = new Intent(getActivity(), AppSettingsActivity.class);
|
||||
intent.setData(ContentUris.withAppendedId(KeychainContract.ApiApps.CONTENT_URI, id));
|
||||
intent.setData(KeychainContract.ApiApps.buildByPackageNameUri(selectedPackageName));
|
||||
startActivity(intent);
|
||||
}
|
||||
});
|
||||
@ -79,7 +81,10 @@ public class AppsListFragment extends ListFragment implements
|
||||
}
|
||||
|
||||
// These are the Contacts rows that we will retrieve.
|
||||
static final String[] PROJECTION = new String[]{ApiApps._ID, ApiApps.PACKAGE_NAME};
|
||||
static final String[] PROJECTION = new String[]{
|
||||
ApiApps._ID, // 0
|
||||
ApiApps.PACKAGE_NAME // 1
|
||||
};
|
||||
|
||||
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
|
||||
// This is called when a new Loader needs to be created. This
|
||||
@ -119,6 +124,25 @@ public class AppsListFragment extends ListFragment implements
|
||||
mPM = context.getApplicationContext().getPackageManager();
|
||||
}
|
||||
|
||||
/**
|
||||
* Similar to CursorAdapter.getItemId().
|
||||
* Required to build Uris for api app view, which is not based on row ids
|
||||
*
|
||||
* @param position
|
||||
* @return
|
||||
*/
|
||||
public String getItemPackageName(int position) {
|
||||
if (mDataValid && mCursor != null) {
|
||||
if (mCursor.moveToPosition(position)) {
|
||||
return mCursor.getString(1);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bindView(View view, Context context, Cursor cursor) {
|
||||
TextView text = (TextView) view.findViewById(R.id.api_apps_adapter_item_name);
|
||||
|
@ -46,8 +46,8 @@
|
||||
<org.sufficientlysecure.keychain.ui.widget.FoldableLinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
custom:foldedLabel="@string/btn_encryption_advanced_settings_show"
|
||||
custom:unFoldedLabel="@string/btn_encryption_advanced_settings_hide"
|
||||
custom:foldedLabel="@string/api_settings_show_advanced"
|
||||
custom:unFoldedLabel="@string/api_settings_hide_advanced"
|
||||
custom:foldedIcon="fa-chevron-right"
|
||||
custom:unFoldedIcon="fa-chevron-down">
|
||||
|
||||
|
@ -12,10 +12,24 @@
|
||||
|
||||
<fragment
|
||||
android:id="@+id/api_app_settings_fragment"
|
||||
android:name="org.sufficientlysecure.keychain.service.remote.AppSettingsFragment"
|
||||
android:name="org.sufficientlysecure.keychain.remote.ui.AppSettingsFragment"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
tools:layout="@layout/api_app_settings_fragment" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/api_settings_accounts"
|
||||
android:textAppearance="?android:attr/textAppearanceMedium" />
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/api_accounts_list_fragment"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
android:paddingLeft="4dp"
|
||||
android:paddingRight="4dp" />
|
||||
|
||||
</LinearLayout>
|
||||
</ScrollView>
|
||||
|
@ -39,8 +39,8 @@
|
||||
<org.sufficientlysecure.keychain.ui.widget.FoldableLinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
custom:foldedLabel="@string/btn_encryption_advanced_settings_show"
|
||||
custom:unFoldedLabel="@string/btn_encryption_advanced_settings_hide"
|
||||
custom:foldedLabel="@string/api_settings_show_info"
|
||||
custom:unFoldedLabel="@string/api_settings_hide_info"
|
||||
custom:foldedIcon="fa-chevron-right"
|
||||
custom:unFoldedIcon="fa-chevron-down">
|
||||
|
||||
|
@ -412,6 +412,8 @@
|
||||
|
||||
<!-- Remote API -->
|
||||
<string name="api_no_apps">No registered applications!\n\nThird-party applications can request access to OpenKeychain. After granting access, they will be listed here.</string>
|
||||
<string name="api_settings_show_info">Show advanced information</string>
|
||||
<string name="api_settings_hide_info">Hide advanced information</string>
|
||||
<string name="api_settings_show_advanced">Show advanced settings</string>
|
||||
<string name="api_settings_hide_advanced">Hide advanced settings</string>
|
||||
<string name="api_settings_no_key">No key selected</string>
|
||||
@ -421,6 +423,8 @@
|
||||
<string name="api_settings_revoke">Revoke access</string>
|
||||
<string name="api_settings_package_name">Package Name</string>
|
||||
<string name="api_settings_package_signature">SHA-256 of Package Signature</string>
|
||||
<string name="api_settings_accounts">Accounts</string>
|
||||
<string name="api_settings_accounts_empty">No accounts attached to this application.</string>
|
||||
<string name="api_register_text">The displayed application requests access to OpenKeychain.\nAllow access?\n\nWARNING: If you do not know why this screen appeared, disallow access! You can revoke access later using the \'Registered Applications\' screen.</string>
|
||||
<string name="api_register_allow">Allow access</string>
|
||||
<string name="api_register_disallow">Disallow access</string>
|
||||
|
Loading…
Reference in New Issue
Block a user