612: Replaced StartActivityForResult with ResultLaunchers r=TheLastProject a=Kethen

redoing #470

currently spotBug complains about an InputStream is not being closed properly, which it didn't catch before the refactoring

I'd suggest moving opening an inputStream inside the import thread

Co-authored-by: Katharine <kwchuiaa@connect.ust.hk>
Co-authored-by: Katharine Chui <kwchuiaa@connect.ust.hk>
This commit is contained in:
bors[bot]
2021-11-23 18:17:36 +00:00
committed by GitHub
3 changed files with 156 additions and 160 deletions

View File

@@ -10,14 +10,20 @@ import android.os.Bundle;
import android.text.InputType;
import android.util.Log;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.EditText;
import android.widget.FrameLayout;
import android.widget.Toast;
import java.io.File;
import androidx.activity.result.ActivityResultLauncher;
import androidx.activity.result.contract.ActivityResultContracts;
import androidx.appcompat.app.ActionBar;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.widget.Toolbar;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
@@ -26,11 +32,6 @@ import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;
import androidx.appcompat.app.ActionBar;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.widget.Toolbar;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
import protect.card_locker.async.TaskHandler;
import protect.card_locker.importexport.DataFormat;
import protect.card_locker.importexport.ImportExportResult;
@@ -39,8 +40,6 @@ public class ImportExportActivity extends CatimaAppCompatActivity {
private static final String TAG = "Catima";
private static final int PERMISSIONS_EXTERNAL_STORAGE = 1;
private static final int CHOOSE_EXPORT_LOCATION = 2;
private static final int IMPORT = 3;
private ImportExportTask importExporter;
@@ -49,6 +48,10 @@ public class ImportExportActivity extends CatimaAppCompatActivity {
private DataFormat importDataFormat;
private String exportPassword;
private ActivityResultLauncher<Intent> fileCreateLauncher;
private ActivityResultLauncher<String> fileOpenLauncher;
private ActivityResultLauncher<Intent> filePickerLauncher;
final private TaskHandler mTasks = new TaskHandler();
@Override
@@ -76,6 +79,49 @@ public class ImportExportActivity extends CatimaAppCompatActivity {
PERMISSIONS_EXTERNAL_STORAGE);
}
// would use ActivityResultContracts.CreateDocument() but mime type cannot be set
fileCreateLauncher = registerForActivityResult(new ActivityResultContracts.StartActivityForResult(), result -> {
Intent intent = result.getData();
if (intent == null) {
Log.e(TAG, "Activity returned NULL data");
return;
}
Uri uri = intent.getData();
if (uri == null) {
Log.e(TAG, "Activity returned NULL uri");
return;
}
try {
OutputStream writer = getContentResolver().openOutputStream(uri);
Log.e(TAG, "Starting file export with: " + result.toString());
startExport(writer, uri, exportPassword.toCharArray(), true);
} catch (IOException e) {
Log.e(TAG, "Failed to export file: " + result.toString(), e);
onExportComplete(ImportExportResult.GenericFailure, uri);
}
});
fileOpenLauncher = registerForActivityResult(new ActivityResultContracts.GetContent(), result -> {
if (result == null) {
Log.e(TAG, "Activity returned NULL data");
return;
}
openFileForImport(result, null);
});
filePickerLauncher = registerForActivityResult(new ActivityResultContracts.StartActivityForResult(), result -> {
Intent intent = result.getData();
if (intent == null) {
Log.e(TAG, "Activity returned NULL data");
return;
}
Uri uri = intent.getData();
if (uri == null) {
Log.e(TAG, "Activity returned NULL uri");
return;
}
openFileForImport(intent.getData(), null);
});
// Check that there is a file manager available
final Intent intentCreateDocumentAction = new Intent(Intent.ACTION_CREATE_DOCUMENT);
intentCreateDocumentAction.addCategory(Intent.CATEGORY_OPENABLE);
@@ -83,60 +129,57 @@ public class ImportExportActivity extends CatimaAppCompatActivity {
intentCreateDocumentAction.putExtra(Intent.EXTRA_TITLE, "catima.zip");
Button exportButton = findViewById(R.id.exportButton);
exportButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
AlertDialog.Builder builder = new AlertDialog.Builder(ImportExportActivity.this);
builder.setTitle(R.string.exportPassword);
exportButton.setOnClickListener(v -> {
AlertDialog.Builder builder = new AlertDialog.Builder(ImportExportActivity.this);
builder.setTitle(R.string.exportPassword);
FrameLayout container = new FrameLayout(ImportExportActivity.this);
FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
params.leftMargin = 50;
params.rightMargin = 50;
FrameLayout container = new FrameLayout(ImportExportActivity.this);
FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
params.leftMargin = 50;
params.rightMargin = 50;
final EditText input = new EditText(ImportExportActivity.this);
input.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_PASSWORD);
input.setLayoutParams(params);
input.setHint(R.string.exportPasswordHint);
final EditText input = new EditText(ImportExportActivity.this);
input.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_PASSWORD);
input.setLayoutParams(params);
input.setHint(R.string.exportPasswordHint);
container.addView(input);
builder.setView(container);
builder.setPositiveButton(R.string.ok, (dialogInterface, i) -> {
exportPassword = input.getText().toString();
chooseFileWithIntent(intentCreateDocumentAction, CHOOSE_EXPORT_LOCATION);
});
builder.setNegativeButton(R.string.cancel, (dialogInterface, i) -> dialogInterface.cancel());
builder.show();
container.addView(input);
builder.setView(container);
builder.setPositiveButton(R.string.ok, (dialogInterface, i) -> {
exportPassword = input.getText().toString();
try {
fileCreateLauncher.launch(intentCreateDocumentAction);
} catch (ActivityNotFoundException e) {
Toast.makeText(getApplicationContext(), R.string.failedOpeningFileManager, Toast.LENGTH_LONG).show();
Log.e(TAG, "No activity found to handle intent", e);
}
});
builder.setNegativeButton(R.string.cancel, (dialogInterface, i) -> dialogInterface.cancel());
builder.show();
}
});
// Check that there is a file manager available
final Intent intentGetContentAction = new Intent(Intent.ACTION_GET_CONTENT);
intentGetContentAction.addCategory(Intent.CATEGORY_OPENABLE);
intentGetContentAction.setType("*/*");
Button importFilesystem = findViewById(R.id.importOptionFilesystemButton);
importFilesystem.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
chooseImportType(intentGetContentAction);
}
});
importFilesystem.setOnClickListener(v -> chooseImportType(false));
// Check that there is an app that data can be imported from
final Intent intentPickAction = new Intent(Intent.ACTION_PICK);
Button importApplication = findViewById(R.id.importOptionApplicationButton);
importApplication.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
chooseImportType(intentPickAction);
}
});
importApplication.setOnClickListener(v -> chooseImportType(true));
}
private void chooseImportType(Intent baseIntent) {
private void openFileForImport(Uri uri, char[] password) {
try {
InputStream reader = getContentResolver().openInputStream(uri);
Log.e(TAG, "Starting file import with: " + uri.toString());
startImport(reader, uri, importDataFormat, password, true);
} catch (IOException e) {
Log.e(TAG, "Failed to import file: " + uri.toString(), e);
onImportComplete(ImportExportResult.GenericFailure, uri, importDataFormat);
}
}
private void chooseImportType(boolean choosePicker) {
List<CharSequence> betaImportOptions = new ArrayList<>();
betaImportOptions.add("Fidme");
betaImportOptions.add("Stocard");
@@ -194,7 +237,17 @@ public class ImportExportActivity extends CatimaAppCompatActivity {
.setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
chooseFileWithIntent(baseIntent, IMPORT);
try {
if (choosePicker) {
final Intent intentPickAction = new Intent(Intent.ACTION_PICK);
filePickerLauncher.launch(intentPickAction);
} else {
fileOpenLauncher.launch("*/*");
}
} catch (ActivityNotFoundException e) {
Toast.makeText(getApplicationContext(), R.string.failedOpeningFileManager, Toast.LENGTH_LONG).show();
Log.e(TAG, "No activity found to handle intent", e);
}
}
})
.setNegativeButton(R.string.cancel, null)
@@ -297,7 +350,7 @@ public class ImportExportActivity extends CatimaAppCompatActivity {
builder.setView(input);
builder.setPositiveButton(R.string.ok, (dialogInterface, i) -> {
activityResultParser(IMPORT, RESULT_OK, uri, input.getText().toString().toCharArray());
openFileForImport(uri, input.getText().toString().toCharArray());
});
builder.setNegativeButton(R.string.cancel, (dialogInterface, i) -> dialogInterface.cancel());
@@ -373,69 +426,4 @@ public class ImportExportActivity extends CatimaAppCompatActivity {
builder.create().show();
}
private void chooseFileWithIntent(Intent intent, int requestCode) {
try {
startActivityForResult(intent, requestCode);
} catch (ActivityNotFoundException e) {
Toast.makeText(getApplicationContext(), R.string.failedOpeningFileManager, Toast.LENGTH_LONG).show();
Log.e(TAG, "No activity found to handle intent", e);
}
}
private void activityResultParser(int requestCode, int resultCode, Uri uri, char[] password) {
if (resultCode != RESULT_OK) {
Log.w(TAG, "Failed onActivityResult(), result=" + resultCode);
return;
}
if (uri == null) {
Log.e(TAG, "Activity returned a NULL URI");
return;
}
try {
if (requestCode == CHOOSE_EXPORT_LOCATION) {
OutputStream writer;
if (uri.getScheme() != null) {
writer = getContentResolver().openOutputStream(uri);
} else {
writer = new FileOutputStream(new File(uri.toString()));
}
Log.e(TAG, "Starting file export with: " + uri.toString());
startExport(writer, uri, exportPassword.toCharArray(), true);
} else {
InputStream reader;
if (uri.getScheme() != null) {
reader = getContentResolver().openInputStream(uri);
} else {
reader = new FileInputStream(new File(uri.toString()));
}
Log.e(TAG, "Starting file import with: " + uri.toString());
startImport(reader, uri, importDataFormat, password, true);
}
} catch (IOException e) {
Log.e(TAG, "Failed to import/export file: " + uri.toString(), e);
if (requestCode == CHOOSE_EXPORT_LOCATION) {
onExportComplete(ImportExportResult.GenericFailure, uri);
} else {
onImportComplete(ImportExportResult.GenericFailure, uri, importDataFormat);
}
}
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (data == null) {
Log.e(TAG, "Activity returned NULL data");
return;
}
activityResultParser(requestCode, resultCode, data.getData(), null);
}
}

View File

@@ -26,12 +26,15 @@ import java.util.Arrays;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
import androidx.activity.result.ActivityResultLauncher;
import androidx.activity.result.contract.ActivityResultContracts;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.view.ActionMode;
import androidx.appcompat.widget.SearchView;
import androidx.appcompat.widget.Toolbar;
import androidx.core.splashscreen.SplashScreen;
import androidx.recyclerview.widget.RecyclerView;
import protect.card_locker.preferences.SettingsActivity;
public class MainActivity extends CatimaAppCompatActivity implements LoyaltyCardCursorAdapter.CardAdapterListener, GestureDetector.OnGestureListener {
@@ -52,6 +55,9 @@ public class MainActivity extends CatimaAppCompatActivity implements LoyaltyCard
private View mNoMatchingCardsText;
private View mNoGroupCardsText;
private ActivityResultLauncher<Intent> mMainRequestLauncher;
private ActivityResultLauncher<Intent> mBarcodeScannerLauncher;
private ActionMode.Callback mCurrentActionModeCallback = new ActionMode.Callback() {
@Override
public boolean onCreateActionMode(ActionMode inputMode, Menu inputMenu) {
@@ -260,6 +266,34 @@ public class MainActivity extends CatimaAppCompatActivity implements LoyaltyCard
.show();
}
*/
mMainRequestLauncher = registerForActivityResult(new ActivityResultContracts.StartActivityForResult(), result -> {
// We're coming back from another view so clear the search
// We only do this now to prevent a flash of all entries right after picking one
mFilter = "";
if (mMenu != null) {
MenuItem searchItem = mMenu.findItem(R.id.action_search);
searchItem.collapseActionView();
}
});
mBarcodeScannerLauncher = registerForActivityResult(new ActivityResultContracts.StartActivityForResult(), result -> {
Intent intent = result.getData();
BarcodeValues barcodeValues = Utils.parseSetBarcodeActivityResult(Utils.BARCODE_SCAN, result.getResultCode(), intent, this);
if (!barcodeValues.isEmpty()) {
Intent newIntent = new Intent(getApplicationContext(), LoyaltyCardEditActivity.class);
Bundle newBundle = new Bundle();
newBundle.putString(LoyaltyCardEditActivity.BUNDLE_BARCODETYPE, barcodeValues.format());
newBundle.putString(LoyaltyCardEditActivity.BUNDLE_CARDID, barcodeValues.content());
Bundle inputBundle = intent.getExtras();
if (inputBundle != null && inputBundle.getString(LoyaltyCardEditActivity.BUNDLE_ADDGROUP) != null) {
newBundle.putString(LoyaltyCardEditActivity.BUNDLE_ADDGROUP, inputBundle.getString(LoyaltyCardEditActivity.BUNDLE_ADDGROUP));
}
newIntent.putExtras(newBundle);
startActivity(newIntent);
}
});
}
@Override
@@ -320,44 +354,11 @@ public class MainActivity extends CatimaAppCompatActivity implements LoyaltyCard
bundle.putString(LoyaltyCardEditActivity.BUNDLE_ADDGROUP, groupsTabLayout.getTabAt(selectedTab).getText().toString());
}
intent.putExtras(bundle);
startActivityForResult(intent, Utils.BARCODE_SCAN);
mBarcodeScannerLauncher.launch(intent);
});
addButton.bringToFront();
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent intent) {
super.onActivityResult(requestCode, resultCode, intent);
if (requestCode == Utils.MAIN_REQUEST) {
// We're coming back from another view so clear the search
// We only do this now to prevent a flash of all entries right after picking one
mFilter = "";
if (mMenu != null) {
MenuItem searchItem = mMenu.findItem(R.id.action_search);
searchItem.collapseActionView();
}
updateLoyaltyCardList();
return;
}
BarcodeValues barcodeValues = Utils.parseSetBarcodeActivityResult(requestCode, resultCode, intent, this);
if (!barcodeValues.isEmpty()) {
Intent newIntent = new Intent(getApplicationContext(), LoyaltyCardEditActivity.class);
Bundle newBundle = new Bundle();
newBundle.putString(LoyaltyCardEditActivity.BUNDLE_BARCODETYPE, barcodeValues.format());
newBundle.putString(LoyaltyCardEditActivity.BUNDLE_CARDID, barcodeValues.content());
Bundle inputBundle = intent.getExtras();
if (inputBundle != null && inputBundle.getString(LoyaltyCardEditActivity.BUNDLE_ADDGROUP) != null) {
newBundle.putString(LoyaltyCardEditActivity.BUNDLE_ADDGROUP, inputBundle.getString(LoyaltyCardEditActivity.BUNDLE_ADDGROUP));
}
newIntent.putExtras(newBundle);
startActivity(newIntent);
}
}
@Override
public void onBackPressed() {
if (mMenu != null) {
@@ -542,25 +543,25 @@ public class MainActivity extends CatimaAppCompatActivity implements LoyaltyCard
if (id == R.id.action_manage_groups) {
Intent i = new Intent(getApplicationContext(), ManageGroupsActivity.class);
startActivityForResult(i, Utils.MAIN_REQUEST);
mMainRequestLauncher.launch(i);
return true;
}
if (id == R.id.action_import_export) {
Intent i = new Intent(getApplicationContext(), ImportExportActivity.class);
startActivityForResult(i, Utils.MAIN_REQUEST);
mMainRequestLauncher.launch(i);
return true;
}
if (id == R.id.action_settings) {
Intent i = new Intent(getApplicationContext(), SettingsActivity.class);
startActivityForResult(i, Utils.MAIN_REQUEST);
mMainRequestLauncher.launch(i);
return true;
}
if (id == R.id.action_about) {
Intent i = new Intent(getApplicationContext(), AboutActivity.class);
startActivityForResult(i, Utils.MAIN_REQUEST);
mMainRequestLauncher.launch(i);
return true;
}
@@ -728,7 +729,7 @@ public class MainActivity extends CatimaAppCompatActivity implements LoyaltyCard
ShortcutHelper.updateShortcuts(MainActivity.this, loyaltyCard);
startActivityForResult(i, Utils.MAIN_REQUEST);
mMainRequestLauncher.launch(i);
}
}
}

View File

@@ -20,6 +20,8 @@ import com.journeyapps.barcodescanner.DecoratedBarcodeView;
import java.util.List;
import androidx.activity.result.ActivityResultLauncher;
import androidx.activity.result.contract.ActivityResultContracts;
import androidx.appcompat.app.ActionBar;
import androidx.appcompat.widget.Toolbar;
@@ -39,6 +41,10 @@ public class ScanActivity extends CatimaAppCompatActivity {
private String addGroup;
private boolean torch = false;
private ActivityResultLauncher<Intent> manualAddLauncher;
// can't use the pre-made contract because that launches the file manager for image type instead of gallery
private ActivityResultLauncher<Intent> photoPickerLauncher;
private void extractIntentFields(Intent intent) {
final Bundle b = intent.getExtras();
cardId = b != null ? b.getString(LoyaltyCardEditActivity.BUNDLE_CARDID) : null;
@@ -60,6 +66,8 @@ public class ScanActivity extends CatimaAppCompatActivity {
extractIntentFields(getIntent());
manualAddLauncher = registerForActivityResult(new ActivityResultContracts.StartActivityForResult(), result -> handleActivityResult(Utils.SELECT_BARCODE_REQUEST, result.getResultCode(), result.getData()));
photoPickerLauncher = registerForActivityResult(new ActivityResultContracts.StartActivityForResult(), result -> handleActivityResult(Utils.BARCODE_IMPORT_FROM_IMAGE_FILE, result.getResultCode(), result.getData()));
findViewById(R.id.add_from_image).setOnClickListener(this::addFromImage);
findViewById(R.id.add_manually).setOnClickListener(this::addManually);
@@ -159,8 +167,7 @@ public class ScanActivity extends CatimaAppCompatActivity {
return super.onOptionsItemSelected(item);
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent intent) {
private void handleActivityResult(int requestCode, int resultCode, Intent intent) {
super.onActivityResult(requestCode, resultCode, intent);
BarcodeValues barcodeValues;
@@ -193,12 +200,12 @@ public class ScanActivity extends CatimaAppCompatActivity {
b.putString("initialCardId", cardId);
i.putExtras(b);
}
startActivityForResult(i, Utils.SELECT_BARCODE_REQUEST);
manualAddLauncher.launch(i);
}
public void addFromImage(View view) {
Intent photoPickerIntent = new Intent(Intent.ACTION_PICK);
photoPickerIntent.setType("image/*");
startActivityForResult(photoPickerIntent, Utils.BARCODE_IMPORT_FROM_IMAGE_FILE);
photoPickerLauncher.launch(photoPickerIntent);
}
}