From 9542dc0e12a61535c2866a70cdd9266aff6cd9d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?= Date: Wed, 26 Mar 2014 13:07:32 +0100 Subject: Accounts API, user interface --- .../remote/ui/AccountSettingsActivity.java | 110 ++++++++++++++++++ .../keychain/remote/ui/AccountsListFragment.java | 127 ++++++++++----------- .../keychain/remote/ui/AppSettingsActivity.java | 38 +++--- .../keychain/remote/ui/AppSettingsFragment.java | 10 +- 4 files changed, 194 insertions(+), 91 deletions(-) create mode 100644 OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AccountSettingsActivity.java (limited to 'OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/remote') diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AccountSettingsActivity.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AccountSettingsActivity.java new file mode 100644 index 000000000..1092c7dc8 --- /dev/null +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AccountSettingsActivity.java @@ -0,0 +1,110 @@ +/* + * Copyright (C) 2013 Dominik Schürmann + * + * 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 . + */ + +package org.sufficientlysecure.keychain.remote.ui; + +import android.content.Intent; +import android.net.Uri; +import android.os.Bundle; +import android.support.v7.app.ActionBarActivity; +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.ProviderHelper; +import org.sufficientlysecure.keychain.remote.AccountSettings; +import org.sufficientlysecure.keychain.util.Log; + +public class AccountSettingsActivity extends ActionBarActivity { + private Uri mAccountUri; + + private AccountSettingsFragment mAccountSettingsFragment; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + // Inflate a "Done" custom action bar + ActionBarHelper.setOneButtonView(getSupportActionBar(), + R.string.api_settings_save, R.drawable.ic_action_done, + new View.OnClickListener() { + @Override + public void onClick(View v) { + // "Done" + save(); + } + }); + + setContentView(R.layout.api_account_settings_activity); + + mAccountSettingsFragment = (AccountSettingsFragment) getSupportFragmentManager().findFragmentById( + R.id.api_account_settings_fragment); + + Intent intent = getIntent(); + mAccountUri = intent.getData(); + if (mAccountUri == null) { + Log.e(Constants.TAG, "Intent data missing. Should be Uri of app!"); + finish(); + return; + } else { + Log.d(Constants.TAG, "uri: " + mAccountUri); + loadData(savedInstanceState, mAccountUri); + } + } + +// @Override +// public boolean onCreateOptionsMenu(Menu menu) { +// super.onCreateOptionsMenu(menu); +// getMenuInflater().inflate(R.menu.api_app_settings, menu); +// return true; +// } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + switch (item.getItemId()) { + case R.id.menu_api_settings_revoke: + deleteAccount(); + return true; + case R.id.menu_api_settings_cancel: + finish(); + return true; + } + return super.onOptionsItemSelected(item); + } + + private void loadData(Bundle savedInstanceState, Uri accountUri) { + // TODO: load this also like other fragment with newInstance arguments? + AccountSettings settings = ProviderHelper.getApiAccountSettings(this, accountUri); + mAccountSettingsFragment.setAccSettings(settings); + } + + private void deleteAccount() { + if (getContentResolver().delete(mAccountUri, null, null) <= 0) { + throw new RuntimeException(); + } + finish(); + } + + private void save() { + ProviderHelper.updateApiAccount(this, mAccountSettingsFragment.getAccSettings(), mAccountUri); + + finish(); + } + +} diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AccountsListFragment.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AccountsListFragment.java index 853dc2d3c..22ee7db76 100644 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AccountsListFragment.java +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AccountsListFragment.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013 Dominik Schürmann + * Copyright (C) 2014 Dominik Schürmann * * 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 @@ -17,35 +17,35 @@ package org.sufficientlysecure.keychain.remote.ui; -import android.annotation.TargetApi; -import android.content.ContentUris; +import android.content.Context; import android.content.Intent; import android.database.Cursor; import android.net.Uri; -import android.os.Build; import android.os.Bundle; 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.SimpleCursorAdapter; +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; -// TODO: make compat with < 11 -@TargetApi(Build.VERSION_CODES.HONEYCOMB) public class AccountsListFragment extends ListFragment implements LoaderManager.LoaderCallbacks { private static final String ARG_DATA_URI = "uri"; // This is the Adapter being used to display the list's data. - SimpleCursorAdapter mAdapter; + AccountsAdapter mAdapter; private Uri mDataUri; @@ -72,10 +72,14 @@ public class AccountsListFragment extends ListFragment implements 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); + String selectedAccountName = mAdapter.getItemAccountName(position); + Uri accountUri = mDataUri.buildUpon().appendEncodedPath(selectedAccountName).build(); + Log.d(Constants.TAG, "accountUri: " + accountUri); + + // edit account settings + Intent intent = new Intent(getActivity(), AccountSettingsActivity.class); + intent.setData(accountUri); + startActivity(intent); } }); @@ -87,12 +91,7 @@ public class AccountsListFragment extends ListFragment implements setHasOptionsMenu(true); // Create an empty adapter we will use to display the loaded data. - mAdapter = new SimpleCursorAdapter(getActivity(), - android.R.layout.simple_list_item_1, - null, - new String[]{KeychainContract.ApiAccounts.ACCOUNT_NAME}, - new int[]{android.R.id.text1}, - 0); + mAdapter = new AccountsAdapter(getActivity(), null, 0); setListAdapter(mAdapter); // Prepare the loader. Either re-connect with an existing one, @@ -102,15 +101,13 @@ public class AccountsListFragment extends ListFragment implements // These are the Contacts rows that we will retrieve. static final String[] PROJECTION = new String[]{ - KeychainContract.ApiAccounts._ID, - KeychainContract.ApiAccounts.ACCOUNT_NAME}; + KeychainContract.ApiAccounts._ID, // 0 + KeychainContract.ApiAccounts.ACCOUNT_NAME // 1 + }; public Loader onCreateLoader(int id, Bundle args) { // This is called when a new Loader needs to be created. This // 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); // Now create and return a CursorLoader that will take care of // creating a Cursor for the data being displayed. @@ -131,46 +128,46 @@ public class AccountsListFragment extends ListFragment implements mAdapter.swapCursor(null); } -// private class RegisteredAppsAdapter extends CursorAdapter { -// -// private LayoutInflater mInflater; -// private PackageManager mPM; -// -// public RegisteredAppsAdapter(Context context, Cursor c, int flags) { -// super(context, c, flags); -// -// mInflater = LayoutInflater.from(context); -// mPM = context.getApplicationContext().getPackageManager(); -// } -// -// @Override -// public void bindView(View view, Context context, Cursor cursor) { -// TextView text = (TextView) view.findViewById(R.id.api_apps_adapter_item_name); -// ImageView icon = (ImageView) view.findViewById(R.id.api_apps_adapter_item_icon); -// -// String packageName = cursor.getString(cursor.getColumnIndex(ApiApps.PACKAGE_NAME)); -// if (packageName != null) { -// // get application name -// try { -// ApplicationInfo ai = mPM.getApplicationInfo(packageName, 0); -// -// text.setText(mPM.getApplicationLabel(ai)); -// icon.setImageDrawable(mPM.getApplicationIcon(ai)); -// } catch (final PackageManager.NameNotFoundException e) { -// // fallback -// text.setText(packageName); -// } -// } else { -// // fallback -// text.setText(packageName); -// } -// -// } -// -// @Override -// public View newView(Context context, Cursor cursor, ViewGroup parent) { -// return mInflater.inflate(R.layout.api_apps_adapter_list_item, null); -// } -// } + private class AccountsAdapter extends CursorAdapter { + private LayoutInflater mInflater; + + public AccountsAdapter(Context context, Cursor c, int flags) { + super(context, c, flags); + + mInflater = LayoutInflater.from(context); + } + + /** + * Similar to CursorAdapter.getItemId(). + * Required to build Uris for api app view, which is not based on row ids + * + * @param position + * @return + */ + public String getItemAccountName(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_accounts_adapter_item_name); + + String accountName = cursor.getString(1); + text.setText(accountName); + } + + @Override + public View newView(Context context, Cursor cursor, ViewGroup parent) { + return mInflater.inflate(R.layout.api_accounts_adapter_list_item, null); + } + } } diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AppSettingsActivity.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AppSettingsActivity.java index 33cde49ba..e4b943734 100644 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AppSettingsActivity.java +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AppSettingsActivity.java @@ -18,16 +18,17 @@ package org.sufficientlysecure.keychain.remote.ui; import android.content.Intent; +import android.content.pm.ApplicationInfo; +import android.content.pm.PackageManager; import android.net.Uri; import android.os.Bundle; +import android.support.v7.app.ActionBar; 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; @@ -43,16 +44,11 @@ public class AppSettingsActivity extends ActionBarActivity { protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - // Inflate a "Done" custom action bar - ActionBarHelper.setOneButtonView(getSupportActionBar(), - R.string.api_settings_save, R.drawable.ic_action_done, - new View.OnClickListener() { - @Override - public void onClick(View v) { - // "Done" - save(); - } - }); + // let the actionbar look like Android's contact app + ActionBar actionBar = getSupportActionBar(); + actionBar.setDisplayHomeAsUpEnabled(true); + actionBar.setIcon(android.R.color.transparent); + actionBar.setHomeButtonEnabled(true); setContentView(R.layout.api_app_settings_activity); @@ -96,6 +92,18 @@ public class AppSettingsActivity extends ActionBarActivity { AppSettings settings = ProviderHelper.getApiAppSettings(this, appUri); mSettingsFragment.setAppSettings(settings); + String appName; + PackageManager pm = getPackageManager(); + try { + ApplicationInfo ai = pm.getApplicationInfo(settings.getPackageName(), 0); + appName = (String) pm.getApplicationLabel(ai); + } catch (PackageManager.NameNotFoundException e) { + // fallback + appName = settings.getPackageName(); + } + setTitle(appName); + + Uri accountsUri = appUri.buildUpon().appendPath(KeychainContract.PATH_ACCOUNTS).build(); Log.d(Constants.TAG, "accountsUri: " + accountsUri); startListFragment(savedInstanceState, accountsUri); @@ -128,10 +136,4 @@ public class AppSettingsActivity extends ActionBarActivity { finish(); } - private void save() { - ProviderHelper.updateApiApp(this, mSettingsFragment.getAppSettings(), mAppUri); - - finish(); - } - } diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AppSettingsFragment.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AppSettingsFragment.java index 8bcd83fc7..5a6151d88 100644 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AppSettingsFragment.java +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AppSettingsFragment.java @@ -26,19 +26,13 @@ import android.support.v4.app.Fragment; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; -import android.widget.AdapterView; -import android.widget.AdapterView.OnItemSelectedListener; import android.widget.ImageView; -import android.widget.Spinner; import android.widget.TextView; import org.spongycastle.util.encoders.Hex; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.remote.AppSettings; -import org.sufficientlysecure.keychain.ui.SelectSecretKeyLayoutFragment; -import org.sufficientlysecure.keychain.ui.adapter.KeyValueSpinnerAdapter; -import org.sufficientlysecure.keychain.util.AlgorithmNames; import org.sufficientlysecure.keychain.util.Log; import java.security.MessageDigest; @@ -100,14 +94,14 @@ public class AppSettingsFragment extends Fragment { PackageManager pm = getActivity().getApplicationContext().getPackageManager(); // get application name and icon from package manager - String appName = null; + String appName; Drawable appIcon = null; try { ApplicationInfo ai = pm.getApplicationInfo(packageName, 0); appName = (String) pm.getApplicationLabel(ai); appIcon = pm.getApplicationIcon(ai); - } catch (final NameNotFoundException e) { + } catch (NameNotFoundException e) { // fallback appName = packageName; } -- cgit v1.2.3