Better autofill data transfer between each activity,

New Autofill helper,
Add consultation mode
This commit is contained in:
Jeremy
2018-01-30 21:08:30 +01:00
parent ebe8c90238
commit ffffeb9e85
10 changed files with 568 additions and 204 deletions

View File

@@ -68,7 +68,6 @@ def supportVersion = "26.1.0"
def spongycastleVersion = "1.58.0.0"
dependencies {
androidTestImplementation files('libs/junit4.jar')
implementation "com.android.support:appcompat-v7:$supportVersion"
implementation "com.android.support:design:$supportVersion"
implementation "com.android.support:preference-v7:$supportVersion"

View File

@@ -24,13 +24,12 @@ import android.content.Context;
import android.content.Intent;
import android.content.IntentSender;
import android.os.Build;
import android.os.Bundle;
import android.support.annotation.RequiresApi;
import com.keepassdroid.fileselect.FileSelectActivity;
import com.kunzisoft.keepass.KeePass;
import static com.keepassdroid.PasswordActivity.KEY_AUTOFILL_RESPONSE;
@RequiresApi(api = Build.VERSION_CODES.O)
public class AutoFillAuthActivity extends KeePass {
@@ -41,8 +40,10 @@ public class AutoFillAuthActivity extends KeePass {
}
protected void startFileSelectActivity() {
Intent intent = new Intent(this, FileSelectActivity.class);
intent.putExtra(KEY_AUTOFILL_RESPONSE, true);
startActivityForResult(intent, 0);
// Pass extra for Autofill (EXTRA_ASSIST_STRUCTURE)
Bundle extras = null;
if (getIntent() != null && getIntent().getExtras() != null)
extras = getIntent().getExtras();
FileSelectActivity.launch(this, extras);
}
}

View File

@@ -23,6 +23,7 @@ import android.app.Activity;
import android.app.Dialog;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.preference.PreferenceManager;
@@ -34,9 +35,8 @@ import android.view.MenuItem;
import android.view.View;
import android.widget.AdapterView.AdapterContextMenuInfo;
import com.kunzisoft.keepass.KeePass;
import com.kunzisoft.keepass.R;
import com.keepassdroid.app.App;
import com.keepassdroid.autofill.AutofillHelper;
import com.keepassdroid.database.PwDatabase;
import com.keepassdroid.database.PwDatabaseV3;
import com.keepassdroid.database.PwDatabaseV4;
@@ -50,6 +50,8 @@ import com.keepassdroid.view.ClickView;
import com.keepassdroid.view.GroupAddEntryView;
import com.keepassdroid.view.GroupRootView;
import com.keepassdroid.view.GroupViewOnlyView;
import com.kunzisoft.keepass.KeePass;
import com.kunzisoft.keepass.R;
public abstract class GroupActivity extends GroupBaseActivity
implements GroupEditFragment.CreateGroupListener, IconPickerFragment.IconPickerListener {
@@ -64,35 +66,44 @@ public abstract class GroupActivity extends GroupBaseActivity
private static final String TAG = "Group Activity:";
public static void Launch(Activity act) {
Launch(act, null);
Launch(act, null, null);
}
public static void Launch(Activity act, Bundle extras) {
Launch(act, null, extras);
}
public static void Launch(Activity act, PwGroup group) {
Intent i;
Launch(act, group, null);
}
public static void Launch(Activity act, PwGroup group, Bundle extras) {
Intent intent;
// Need to use PwDatabase since tree may be null
PwDatabase db = App.getDB().pm;
if ( db instanceof PwDatabaseV3 ) {
i = new Intent(act, GroupActivityV3.class);
intent = new Intent(act, GroupActivityV3.class);
if ( group != null ) {
PwGroupV3 g = (PwGroupV3) group;
i.putExtra(KEY_ENTRY, g.groupId);
intent.putExtra(KEY_ENTRY, g.groupId);
}
} else if ( db instanceof PwDatabaseV4 ) {
i = new Intent(act, GroupActivityV4.class);
intent = new Intent(act, GroupActivityV4.class);
if ( group != null ) {
PwGroupV4 g = (PwGroupV4) group;
i.putExtra(KEY_ENTRY, g.uuid.toString());
intent.putExtra(KEY_ENTRY, g.uuid.toString());
}
} else {
// Reached if db is null
Log.d(TAG, "Tried to launch with null db");
return;
}
act.startActivityForResult(i,0);
if (extras != null)
intent.putExtras(extras);
act.startActivityForResult(intent,0);
}
protected abstract PwGroupId retrieveGroupId(Intent i);
@@ -117,7 +128,10 @@ public abstract class GroupActivity extends GroupBaseActivity
PwGroupId id = retrieveGroupId(intent);
Database db = App.getDB();
readOnly = db.readOnly;
// Force readonly if it's autofill
readOnly = AutofillHelper.isIntentContainsAutofillAuthKey(getIntent()) || db.readOnly;
PwGroup root = db.pm.rootGroup;
if (id == null) {
mGroup = root;
@@ -139,6 +153,8 @@ public abstract class GroupActivity extends GroupBaseActivity
setContentView(new GroupAddEntryView(this));
} else if (addGroupEnabled) {
setContentView(new GroupRootView(this));
View addEntry = findViewById(R.id.add_entry);
addEntry.setVisibility(View.GONE);
} else if (addEntryEnabled) {
setContentView(new GroupAddEntryView(this));
View addGroup = findViewById(R.id.add_group);

View File

@@ -20,12 +20,9 @@
package com.keepassdroid;
import android.app.Activity;
import android.app.PendingIntent;
import android.content.Context;
import android.content.DialogInterface;
import android.content.DialogInterface.OnClickListener;
import android.content.Intent;
import android.content.IntentSender;
import android.content.SharedPreferences;
import android.net.Uri;
import android.os.AsyncTask;
@@ -38,7 +35,6 @@ import android.support.v4.hardware.fingerprint.FingerprintManagerCompat;
import android.support.v7.widget.Toolbar;
import android.text.Editable;
import android.text.TextWatcher;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
@@ -77,7 +73,6 @@ public class PasswordActivity extends LockingActivity
public static final String KEY_DEFAULT_FILENAME = "defaultFileName";
private static final String KEY_PASSWORD = "password";
public static final String KEY_AUTOFILL_RESPONSE = "KEY_AUTOFILL_RESPONSE";
private static final String KEY_LAUNCH_IMMEDIATELY = "launchImmediately";
private Uri mDbUri = null;
@@ -107,20 +102,24 @@ public class PasswordActivity extends LockingActivity
private KeyFileHelper keyFileHelper;
private Intent mReplyIntent;
public static void Launch(
Activity act,
String fileName) throws FileNotFoundException {
Launch(act, fileName, "", null);
}
public static void Launch(
Activity act,
String fileName,
boolean autoFillResponse) throws FileNotFoundException {
Launch(act, fileName, "", autoFillResponse);
Bundle extra) throws FileNotFoundException {
Launch(act, fileName, "", extra);
}
public static void Launch(
Activity act,
String fileName,
String keyFile,
boolean autoFillResponse) throws FileNotFoundException {
Bundle extras) throws FileNotFoundException {
if (EmptyUtils.isNullOrEmpty(fileName)) {
throw new FileNotFoundException();
}
@@ -137,15 +136,12 @@ public class PasswordActivity extends LockingActivity
}
Intent i = new Intent(act, PasswordActivity.class);
i.putExtra(KEY_AUTOFILL_RESPONSE, autoFillResponse);
i.putExtra(UriIntentInitTask.KEY_FILENAME, fileName);
i.putExtra(UriIntentInitTask.KEY_KEYFILE, keyFile);
if (extras != null)
i.putExtras(extras);
act.startActivityForResult(i, 0);
if(autoFillResponse)
act.finish();
}
@Override
@@ -683,15 +679,7 @@ public class PasswordActivity extends LockingActivity
App.clearShutdown();
Handler handler = new Handler();
AfterLoad afterLoad;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O
&& getIntent().getExtras() != null
&& getIntent().getExtras().containsKey(KEY_AUTOFILL_RESPONSE)
&& getIntent().getBooleanExtra(KEY_AUTOFILL_RESPONSE, false)) {
afterLoad = new AfterLoadAutofill(handler, db);
} else {
afterLoad = new AfterLoad(handler, db);
}
AfterLoad afterLoad = new AfterLoad(handler, db);
LoadDB task = new LoadDB(db, PasswordActivity.this, mDbUri, pass, keyfile, afterLoad);
ProgressTask pt = new ProgressTask(PasswordActivity.this, task, R.string.loading_database);
@@ -742,36 +730,18 @@ public class PasswordActivity extends LockingActivity
public void onClick(
DialogInterface dialog,
int which) {
GroupActivity.Launch(PasswordActivity.this);
GroupActivity.Launch(PasswordActivity.this, getIntent().getExtras());
}
});
} else if (mSuccess) {
GroupActivity.Launch(PasswordActivity.this);
GroupActivity.Launch(PasswordActivity.this, getIntent().getExtras());
} else {
displayMessage(PasswordActivity.this);
}
}
}
@RequiresApi(api = Build.VERSION_CODES.O)
private class AfterLoadAutofill extends AfterLoad {
public AfterLoadAutofill(Handler handler, Database db) {
super(handler, db);
}
@Override
public void run() {
if (mSuccess) {
onAutofillResponseSuccess();
} else {
onAutofillResponseFailure();
}
finish();
}
}
private static class UriIntentInitTask extends AsyncTask<Intent, Void, Integer> {
static final String KEY_FILENAME = "fileName";
@@ -848,51 +818,4 @@ public class PasswordActivity extends LockingActivity
}
}
}
@RequiresApi(api = Build.VERSION_CODES.O)
public static IntentSender getAuthIntentSenderForResponse(Context context) {
final Intent intent = new Intent(context, AutoFillAuthActivity.class);
return PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT)
.getIntentSender();
}
@Override
public void finish() {
if (mReplyIntent != null) {
setResult(RESULT_OK, mReplyIntent);
} else {
setResult(RESULT_CANCELED);
}
super.finish();
}
@RequiresApi(api = Build.VERSION_CODES.O)
private void onAutofillResponseFailure() {
Log.w(getClass().getName(), "Failed Autofill auth.");
mReplyIntent = null;
}
@RequiresApi(api = Build.VERSION_CODES.O)
private void onAutofillResponseSuccess() {
/*
Intent intent = getIntent();
Bundle clientState = intent.getBundleExtra(AutofillManager.EXTRA_CLIENT_STATE);
AssistStructure structure = intent.getParcelableExtra(EXTRA_ASSIST_STRUCTURE);
StructureParser parser = new StructureParser(getApplicationContext(), structure);
parser.parseForFill();
AutofillFieldMetadataCollection autofillFields = parser.getAutofillFields();
*/
mReplyIntent = new Intent();
/*
HashMap<String, FilledAutofillFieldCollection> clientFormDataMap =
SharedPrefsAutofillRepository.getInstance().getFilledAutofillFieldCollection
(this, autofillFields.getFocusedHints(), autofillFields.getAllHints());
// TODO Add success results
mReplyIntent.putExtra(EXTRA_AUTHENTICATION_RESULT, AutofillHelper.newResponse
(this, clientState, false, autofillFields, clientFormDataMap));
*/
mReplyIntent.putExtra(android.view.autofill.AutofillManager.EXTRA_AUTHENTICATION_RESULT, "");
}
}

View File

@@ -0,0 +1,173 @@
/*
* Copyright 2017 Brian Pellin, Jeremy Jamet / Kunzisoft.
*
* This file is part of KeePass DX.
*
* KeePass DX 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 2 of the License, or
* (at your option) any later version.
*
* KeePass DX 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 KeePass DX. If not, see <http://www.gnu.org/licenses/>.
*
*/
package com.keepassdroid.autofill;
import android.app.Activity;
import android.app.assist.AssistStructure;
import android.content.Context;
import android.content.Intent;
import android.os.Build;
import android.service.autofill.Dataset;
import android.service.autofill.FillResponse;
import android.service.autofill.SaveInfo;
import android.support.annotation.RequiresApi;
import android.util.Log;
import android.view.autofill.AutofillId;
import android.widget.RemoteViews;
import com.keepassdroid.autofill.dataSource.SharedPrefsAutofillRepository;
import com.keepassdroid.model.FilledAutofillFieldCollection;
import com.kunzisoft.keepass.R;
import java.util.HashMap;
import java.util.Set;
public class AutofillHelper {
private static final int AUTOFILL_RESPONSE_REQUEST_CODE = 81653;
/**
* Define if EXTRA_AUTHENTICATION_RESULT is an extra bundle key present in the Intent
*/
public static boolean isIntentContainsAutofillAuthKey(Intent intent) {
return Build.VERSION.SDK_INT >= Build.VERSION_CODES.O
&& (intent != null
&& intent.getExtras() != null
&& intent.getExtras().containsKey(android.view.autofill.AutofillManager.EXTRA_ASSIST_STRUCTURE));
}
/**
* Method to hit when right key is selected
*/
@RequiresApi(api = Build.VERSION_CODES.O)
private static void onAutofillResponse(Activity activity) {
// TODO Connect this method in each item in GroupActivity
Intent mReplyIntent = null;
Intent intent = activity.getIntent();
if (isIntentContainsAutofillAuthKey(intent)) {
AssistStructure structure = intent.getParcelableExtra(
android.view.autofill.AutofillManager.EXTRA_ASSIST_STRUCTURE);
StructureParser parser = new StructureParser(activity, structure);
parser.parseForFill();
AutofillFieldMetadataCollection autofillFields = parser.getAutofillFields();
mReplyIntent = new Intent();
HashMap<String, FilledAutofillFieldCollection> clientFormDataMap =
SharedPrefsAutofillRepository.getInstance().getFilledAutofillFieldCollection
(activity, autofillFields.getFocusedHints(), autofillFields.getAllHints());
Log.d(activity.getClass().getName(), "Successed Autofill auth.");
mReplyIntent.putExtra(
android.view.autofill.AutofillManager.EXTRA_AUTHENTICATION_RESULT,
AutofillHelper.newResponse
(activity, autofillFields, clientFormDataMap));
activity.setResult(Activity.RESULT_OK, mReplyIntent);
} else {
Log.w(activity.getClass().getName(), "Failed Autofill auth.");
activity.setResult(Activity.RESULT_CANCELED);
}
}
/**
* Utility method to loop and close each activity with return data
*/
public static void onActivityResult(Activity activity, int requestCode, int resultCode, Intent data) {
if (requestCode == AUTOFILL_RESPONSE_REQUEST_CODE) {
if (resultCode == Activity.RESULT_OK) {
if (data != null) {
activity.setResult(Activity.RESULT_OK, data);
} else {
activity.setResult(Activity.RESULT_CANCELED);
}
} else
activity.setResult(Activity.RESULT_CANCELED);
activity.finish();
}
}
/**
* Wraps autofill data in a LoginCredential Dataset object which can then be sent back to the
* client View.
*/
@RequiresApi(api = Build.VERSION_CODES.O)
public static Dataset newDataset(Context context,
AutofillFieldMetadataCollection autofillFields,
FilledAutofillFieldCollection filledAutofillFieldCollection) {
String datasetName = filledAutofillFieldCollection.getDatasetName();
if (datasetName != null) {
Dataset.Builder datasetBuilder;
datasetBuilder = new Dataset.Builder
(newRemoteViews(context.getPackageName(), datasetName));
boolean setValueAtLeastOnce =
filledAutofillFieldCollection.applyToFields(autofillFields, datasetBuilder);
if (setValueAtLeastOnce) {
return datasetBuilder.build();
}
}
return null;
}
@RequiresApi(api = Build.VERSION_CODES.O)
public static RemoteViews newRemoteViews(String packageName, String remoteViewsText) {
RemoteViews presentation =
new RemoteViews(packageName, R.layout.autofill_service_list_item);
presentation.setTextViewText(R.id.text, remoteViewsText);
return presentation;
}
/**
* Wraps autofill data in a Response object (essentially a series of Datasets) which can then
* be sent back to the client View.
*/
@RequiresApi(api = Build.VERSION_CODES.O)
public static FillResponse newResponse(Context context,
AutofillFieldMetadataCollection autofillFields,
HashMap<String, FilledAutofillFieldCollection> clientFormDataMap) {
FillResponse.Builder responseBuilder = new FillResponse.Builder();
if (clientFormDataMap != null) {
Set<String> datasetNames = clientFormDataMap.keySet();
for (String datasetName : datasetNames) {
FilledAutofillFieldCollection filledAutofillFieldCollection =
clientFormDataMap.get(datasetName);
if (filledAutofillFieldCollection != null) {
Dataset dataset = newDataset(context, autofillFields,
filledAutofillFieldCollection);
if (dataset != null) {
responseBuilder.addDataset(dataset);
}
}
}
}
int saveType = autofillFields.getSaveType();
if (saveType != 0) {
setFullSaveInfo(responseBuilder, saveType, autofillFields);
return responseBuilder.build();
} else {
Log.d(AutofillHelper.class.getName(), "These fields are not meant to be saved by autofill.");
return null;
}
}
@RequiresApi(api = Build.VERSION_CODES.O)
private static void setFullSaveInfo(FillResponse.Builder responseBuilder, int saveType,
AutofillFieldMetadataCollection autofillFields) {
AutofillId[] autofillIds = autofillFields.getAutofillIds();
responseBuilder.setSaveInfo(new SaveInfo.Builder(saveType, autofillIds).build());
}
}

View File

@@ -0,0 +1,43 @@
/*
* Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.keepassdroid.autofill.dataSource;
import android.content.Context;
import com.keepassdroid.model.FilledAutofillFieldCollection;
import java.util.HashMap;
import java.util.List;
public interface AutofillDataSource {
/**
* Gets saved FilledAutofillFieldCollection that contains some objects that can autofill fields
* with these {@code autofillHints}.
*/
HashMap<String, FilledAutofillFieldCollection> getFilledAutofillFieldCollection(Context context,
List<String> focusedAutofillHints, List<String> allAutofillHints);
/**
* Stores a collection of Autofill fields.
*/
void saveFilledAutofillFieldCollection(Context context,
FilledAutofillFieldCollection filledAutofillFieldCollection);
/**
* Clears all data.
*/
void clear(Context context);
}

View File

@@ -0,0 +1,144 @@
/*
* Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.keepassdroid.autofill.dataSource;
import android.content.Context;
import android.os.Build;
import android.support.annotation.RequiresApi;
import android.util.ArraySet;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.keepassdroid.model.FilledAutofillFieldCollection;
import java.util.HashMap;
import java.util.List;
import java.util.Set;
/**
* Singleton autofill data repository that stores autofill fields to SharedPreferences.
* <p>
* <p><b>Disclaimer</b>: you should not store sensitive fields like user data unencrypted.
* This is done here only for simplicity and learning purposes.
*/
@RequiresApi(api = Build.VERSION_CODES.O)
public class SharedPrefsAutofillRepository implements AutofillDataSource {
private static final String SHARED_PREF_KEY = "com.example.android.autofill"
+ ".service.datasource.AutofillDataSource";
private static final String CLIENT_FORM_DATA_KEY = "loginCredentialDatasets";
private static final String DATASET_NUMBER_KEY = "datasetNumber";
private static SharedPrefsAutofillRepository sInstance;
private SharedPrefsAutofillRepository() {
}
public static SharedPrefsAutofillRepository getInstance() {
if (sInstance == null) {
sInstance = new SharedPrefsAutofillRepository();
}
return sInstance;
}
@Override
public HashMap<String, FilledAutofillFieldCollection> getFilledAutofillFieldCollection(
Context context, List<String> focusedAutofillHints, List<String> allAutofillHints) {
boolean hasDataForFocusedAutofillHints = false;
HashMap<String, FilledAutofillFieldCollection> clientFormDataMap = new HashMap<>();
Set<String> clientFormDataStringSet = getAllAutofillDataStringSet(context);
for (String clientFormDataString : clientFormDataStringSet) {
Gson gson = new GsonBuilder().excludeFieldsWithoutExposeAnnotation().create();
FilledAutofillFieldCollection filledAutofillFieldCollection =
gson.fromJson(clientFormDataString, FilledAutofillFieldCollection.class);
if (filledAutofillFieldCollection != null) {
if (filledAutofillFieldCollection.helpsWithHints(focusedAutofillHints)) {
// Saved data has data relevant to at least 1 of the hints associated with the
// View in focus.
hasDataForFocusedAutofillHints = true;
}
if (filledAutofillFieldCollection.helpsWithHints(allAutofillHints)) {
// Saved data has data relevant to at least 1 of these hints associated with any
// of the Views in the hierarchy.
clientFormDataMap.put(filledAutofillFieldCollection.getDatasetName(),
filledAutofillFieldCollection);
}
}
}
if (hasDataForFocusedAutofillHints) {
return clientFormDataMap;
} else {
return null;
}
}
@Override
public void saveFilledAutofillFieldCollection(Context context,
FilledAutofillFieldCollection filledAutofillFieldCollection) {
String datasetName = "dataset-" + getDatasetNumber(context);
filledAutofillFieldCollection.setDatasetName(datasetName);
Set<String> allAutofillData = getAllAutofillDataStringSet(context);
Gson gson = new GsonBuilder().excludeFieldsWithoutExposeAnnotation().create();
allAutofillData.add(gson.toJson(filledAutofillFieldCollection));
saveAllAutofillDataStringSet(context, allAutofillData);
incrementDatasetNumber(context);
}
@Override
public void clear(Context context) {
context.getApplicationContext()
.getSharedPreferences(SHARED_PREF_KEY, Context.MODE_PRIVATE)
.edit()
.remove(CLIENT_FORM_DATA_KEY)
.remove(DATASET_NUMBER_KEY)
.apply();
}
private Set<String> getAllAutofillDataStringSet(Context context) {
return context.getApplicationContext()
.getSharedPreferences(SHARED_PREF_KEY, Context.MODE_PRIVATE)
.getStringSet(CLIENT_FORM_DATA_KEY, new ArraySet<String>());
}
private void saveAllAutofillDataStringSet(Context context,
Set<String> allAutofillDataStringSet) {
context.getApplicationContext()
.getSharedPreferences(SHARED_PREF_KEY, Context.MODE_PRIVATE)
.edit()
.putStringSet(CLIENT_FORM_DATA_KEY, allAutofillDataStringSet)
.apply();
}
/**
* For simplicity, datasets will be named in the form "dataset-X" where X means
* this was the Xth dataset saved.
*/
private int getDatasetNumber(Context context) {
return context.getApplicationContext()
.getSharedPreferences(SHARED_PREF_KEY, Context.MODE_PRIVATE)
.getInt(DATASET_NUMBER_KEY, 0);
}
/**
* Every time a dataset is saved, this should be called to increment the dataset number.
* (only important for this service's dataset naming scheme).
*/
private void incrementDatasetNumber(Context context) {
context.getApplicationContext()
.getSharedPreferences(SHARED_PREF_KEY, Context.MODE_PRIVATE)
.edit()
.putInt(DATASET_NUMBER_KEY, getDatasetNumber(context) + 1)
.apply();
}
}

View File

@@ -20,12 +20,14 @@
package com.keepassdroid.fileselect;
import android.Manifest;
import android.app.Activity;
import android.content.ActivityNotFoundException;
import android.content.ContentResolver;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.preference.PreferenceManager;
@@ -47,6 +49,7 @@ import com.keepassdroid.GroupActivity;
import com.keepassdroid.PasswordActivity;
import com.keepassdroid.ProgressTask;
import com.keepassdroid.app.App;
import com.keepassdroid.autofill.AutofillHelper;
import com.keepassdroid.compat.ContentResolverCompat;
import com.keepassdroid.compat.StorageAF;
import com.keepassdroid.database.edit.CreateDB;
@@ -88,21 +91,30 @@ public class FileSelectActivity extends StylishActivity implements
private RecentFileHistory fileHistory;
private boolean recentMode = false;
private boolean autofillResponse = false;
private boolean consultationMode = false;
private EditText openFileNameView;
private AssignPasswordHelper assignPasswordHelper;
private Uri databaseUri;
public static void launch(Activity act) {
launch(act, null);
}
public static void launch(Activity act, Bundle extra) {
Intent intent = new Intent(act, FileSelectActivity.class);
if (extra != null)
intent.putExtras(extra);
act.startActivityForResult(intent, 0);
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if(getIntent().getExtras() != null) {
autofillResponse = getIntent().getExtras().
getBoolean(PasswordActivity.KEY_AUTOFILL_RESPONSE, autofillResponse);
}
if (AutofillHelper.isIntentContainsAutofillAuthKey(getIntent()))
consultationMode = true;
fileHistory = App.getFileHistory();
@@ -127,7 +139,9 @@ public class FileSelectActivity extends StylishActivity implements
String fileName = Util.getEditText(FileSelectActivity.this,
R.id.file_filename);
try {
PasswordActivity.Launch(FileSelectActivity.this, fileName, autofillResponse);
PasswordActivity.Launch(FileSelectActivity.this,
fileName,
getIntent().getExtras());
}
catch (ContentFileNotFoundException e) {
Toast.makeText(FileSelectActivity.this,
@@ -142,12 +156,16 @@ public class FileSelectActivity extends StylishActivity implements
// Create button
View createButton = findViewById(R.id.create_database);
if (!consultationMode) {
createButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
CreateFileDialog createFileDialog = new CreateFileDialog();
createFileDialog.show(getSupportFragmentManager(), "createFileDialog");
}
});
} else {
createButton.setVisibility(View.GONE);
}
View browseButton = findViewById(R.id.browse_button);
browseButton.setOnClickListener(new View.OnClickListener() {
@@ -224,7 +242,9 @@ public class FileSelectActivity extends StylishActivity implements
if (db.exists()) {
try {
PasswordActivity.Launch(FileSelectActivity.this, path, autofillResponse);
PasswordActivity.Launch(FileSelectActivity.this,
path,
getIntent().getExtras());
} catch (Exception e) {
// Ignore exception
}
@@ -232,7 +252,9 @@ public class FileSelectActivity extends StylishActivity implements
}
else {
try {
PasswordActivity.Launch(FileSelectActivity.this, dbUri.toString(), autofillResponse);
PasswordActivity.Launch(FileSelectActivity.this,
dbUri.toString(),
getIntent().getExtras());
} catch (Exception e) {
// Ignore exception
}
@@ -402,7 +424,7 @@ public class FileSelectActivity extends StylishActivity implements
public void afterOpenFile(String fileName, String keyFile) {
try {
PasswordActivity.Launch(FileSelectActivity.this,
fileName, keyFile, autofillResponse);
fileName, keyFile, getIntent().getExtras());
} catch (ContentFileNotFoundException e) {
Toast.makeText(FileSelectActivity.this,
R.string.file_not_found_content, Toast.LENGTH_LONG)

View File

@@ -44,8 +44,7 @@ public class KeePass extends Activity {
}
protected void startFileSelectActivity() {
Intent intent = new Intent(this, FileSelectActivity.class);
startActivityForResult(intent, 0);
FileSelectActivity.launch(this);
}
@Override

View File

@@ -0,0 +1,44 @@
<?xml version="1.0" encoding="utf-8"?><!--
* Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@android:color/white"
android:orientation="horizontal">
<ImageView
android:id="@+id/icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginRight="12dp"
android:layout_marginEnd="12dp"
android:layout_marginLeft="12dp"
android:layout_marginStart="12dp"
android:src="@drawable/ic_key_white_24dp"
android:tint="@color/colorTextPrimary"/>
<TextView
android:id="@+id/text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:paddingRight="12dp"
android:paddingEnd="12dp"
android:paddingLeft="12dp"
android:paddingStart="12dp"
android:textAppearance="?android:attr/textAppearanceListItemSmall" />
</LinearLayout>