Voice Recognition without Google Dialog - java

I am trying to use the Speech recognition without dialog with RecognitionListener, but it doesn't work. The following codes are the way now I use, and the bottom codes (test part) are for checking that could phone receive my commanding. Additionally, I have added permissions Audio. Finally, I don't want there have any button.
This is my first time asking question, so hope I dont violate any unspoken rules.
Thank you very much,
public class Step extends AppCompatActivity {
private final int SPEECH_RECOGNITION_CODE = 1;
private TextView txtOutput;
private Button btnMicrophone;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_step);
txtOutput = (TextView) findViewById(R.id.txt_output);
btnMicrophone = (Button) findViewById(R.id.btn_mic);
startSpeechToText();
btnMicrophone.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
startSpeechToText();
}
});
}
private void startSpeechToText() {
Intent intent = new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH);
intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE, Locale.getDefault());
intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL, RecognizerIntent.LANGUAGE_MODEL_FREE_FORM);
intent.putExtra(RecognizerIntent.EXTRA_PROMPT, "SPEAK");
try {
startActivityForResult(intent, SPEECH_RECOGNITION_CODE);
} catch (ActivityNotFoundException a) {
Toast.makeText(getApplicationContext(), "Sorry! Speech recognition is not supported in this device.", Toast.LENGTH_SHORT).show();
}
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
switch (requestCode) {
case SPEECH_RECOGNITION_CODE: {
if (resultCode == RESULT_OK && null != data) {
ArrayList<String> result = data
.getStringArrayListExtra(RecognizerIntent.EXTRA_RESULTS);
String text = result.get(0);
txtOutput.setText(text);
test(txtOutput.getText().toString());
startSpeechToText();
}
break;
}
}
}
public void test (String com) {
for(int i=0;i<com.length();i++) {
if (com.startsWith("good",i)) {
com = com + "123";
Toast.makeText(CookStep.this, com, Toast.LENGTH_SHORT).show();
}
}
if(com.compareToIgnoreCase("OK")==0){
com=com+"456";
Toast.makeText(CookStep.this, com, Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(CookStep.this, com, Toast.LENGTH_SHORT).show();
}
}
}

Related

How to make ActivityResult output to 2 different textview?

I want to make a speech to text application but output on a different text view. I tried to search the solution on the internet, but most of the answers they only output to 1 text view. I want to make it look like this:
Here is the image of my idea: https://i.imgur.com/M9y4Rcz.png
This is for study purposes. I hope someone can help me
TextView textview1, textview2;
Button btnVoice1, btnVoice2;
textview1= findViewById(R.id.textview1);
textview2= findViewById(R.id.textview2);
btnVoice1 = findViewById(R.id.btnVoice1);
btnVoice2 = findViewById(R.id.btnVoice2);
btnVoice1.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
startVoiceInput();
}
});
btnVoice2.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
startVoiceInput();
}
});
//Function
private void startVoiceInput(){
Intent intent = new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH);
intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL,
RecognizerIntent.LANGUAGE_MODEL_FREE_FORM);
intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE, Locale.getDefault());
intent.putExtra(RecognizerIntent.EXTRA_PROMPT, "Say Something!");
try {
startActivityForResult(intent, REQ_CODE_SPEECH_INPUT);
} catch (ActivityNotFoundException a) {
Toast.makeText(getApplicationContext(),
getString(R.string.speech_not_supported),
Toast.LENGTH_SHORT).show();
}
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
switch (requestCode) {
case REQ_CODE_SPEECH_INPUT: {
if (resultCode == RESULT_OK && null != data) {
ArrayList<String> result = data.getStringArrayListExtra(RecognizerIntent.EXTRA_RESULTS);
textview1.setText(result.get(0));
// how to make textview2 output when btnVoice2 is click
}
break;
}
}
}
For Multiple onActivityResult for single Activity change your code like this:
int REQ_CODE_SPEECH_INPUT=100;
int REQ_CODE_SPEECH_INPUT_SECOND=101;
TextView textview1, textview2;
Button btnVoice1, btnVoice2;
textview1= findViewById(R.id.textview1);
textview2= findViewById(R.id.textview2);
btnVoice1 = findViewById(R.id.btnVoice1);
btnVoice2 = findViewById(R.id.btnVoice2);
btnVoice1.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
startVoiceInput(REQ_CODE_SPEECH_INPUT);
}
});
btnVoice2.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
startVoiceInput(REQ_CODE_SPEECH_INPUT_SECOND);
}
});
private void startVoiceInput(int code){
Intent intent = new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH);
intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL,
RecognizerIntent.LANGUAGE_MODEL_FREE_FORM);
intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE, Locale.getDefault());
intent.putExtra(RecognizerIntent.EXTRA_PROMPT, "Say Something!");
try {
startActivityForResult(intent, code);
} catch (ActivityNotFoundException a) {
Toast.makeText(getApplicationContext(),
getString(R.string.speech_not_supported),
Toast.LENGTH_SHORT).show();
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
switch (requestCode) {
case REQ_CODE_SPEECH_INPUT: {
if (resultCode == RESULT_OK && null != data) {
ArrayList<String> result = data.getStringArrayListExtra(RecognizerIntent.EXTRA_RESULTS);
textview1.setText(result.get(0));
}
break;
}
case REQ_CODE_SPEECH_INPUT_SECOND:{
if (resultCode == RESULT_OK && null != data) {
ArrayList<String> result = data.getStringArrayListExtra(RecognizerIntent.EXTRA_RESULTS);
textview2.setText(result.get(0));
}
break;
}
}
}

startActivityForResult in DialogFragment - QR reader

I have app, which turn on camera QR reader onClick in Fragment,
after that it turns on ServiceActivity
and when you click FAB it turns on TeaDialogFragment, where you click button scan QR it turns on camera QR reader
and it should give result of QR to new Activity (TeaFromQrActivity). But here is a problem - method onActivityResult doesn't called anyway.
TeaDialogFragment.java
public class TeaDialogFragment extends DialogFragment {
public static int BARCODE_READER_REQUEST_CODE = 2;
String qrTeaCode;
private String TAG = TeaDialogFragment.class.getSimpleName();
public TeaDialogFragment() {
// Empty constructor required for DialogFragment
}
public static TeaDialogFragment newInstance(String title) {
TeaDialogFragment frag = new TeaDialogFragment();
Bundle args = new Bundle();
args.putString("title", title);
frag.setArguments(args);
return frag;
}
#Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
String title = getArguments().getString("title");
AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(getActivity());
alertDialogBuilder.setTitle(title);
alertDialogBuilder.setMessage("Message");
alertDialogBuilder.setPositiveButton("scan QR", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
// This code works - it turns on new Activity
// Intent i = new Intent(getActivity().getApplicationContext(), TeaFromQrActivity.class);
// i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
// getActivity().getApplicationContext().startActivity(i);
// This code doesn't works - it doesn't turn on newActivity, when QR Reader have result, and it turn on current Activity
Intent teaDialogIntent = new Intent(getActivity().getApplicationContext(), BarcodeCaptureActivity.class);
teaDialogIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
getActivity().startActivityForResult(teaDialogIntent, BARCODE_READER_REQUEST_CODE);
}
});
alertDialogBuilder.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
if (dialog != null) {
dialog.dismiss();
}
}
});
return alertDialogBuilder.create();
}
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == BARCODE_READER_REQUEST_CODE) {
if (resultCode == CommonStatusCodes.SUCCESS) {
if (data != null) {
Barcode barcode = data.getParcelableExtra(BarcodeCaptureActivity.BarcodeObject);
Intent testIntent = new Intent(getActivity().getApplicationContext(), TeaFromQrActivity.class);
qrTeaCode = "teaQrCode";
testIntent.putExtra(qrTeaCode, barcode.displayValue);
// Start the new activity
startActivity(testIntent);
Log.d(TAG, "Barcode read: " + barcode.displayValue);
} else {
Log.d(TAG, "No barcode captured, intent data is null");
}
} else {
Log.e(TAG, String.format(getString(R.string.barcode_error_format),
CommonStatusCodes.getStatusCodeString(resultCode)));
}
} else {
super.onActivityResult(requestCode, resultCode, data);
}
}
}
TeaFromQrActivity.java
public class TeaFromQrActivity extends AppCompatActivity {
private String teaQR;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_tea_from_qr);
teaQR = getIntent().getExtras().getString("teaQrCode", "null");
Toast.makeText(TeaFromQrActivity.this, "Text from qr: " + teaQR, Toast.LENGTH_SHORT).show();
}
}
Please tell me where I'm wrong.
launch barcode activity like this
Intent intent = new Intent(this, BarcodeCaptureActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivityForResult(intent, BARCODE_READER_REQUEST_CODE);
more detail refer BarcodeCaptureActivity,barcodereader

Zxing Scanner App, How to show a result as a yes or no?

Using zxing on Android Studio with empty activity and 4.4 KitKat. I would like to show the result as a yes or no. I would like to reference a google sheet with the UPC codes. If the UPC is in the spreadsheet already then show "YES" or if the UPC is not in the spreadsheet show "NO". Can I use an "If, Else" in the MainActivity java code using only the UPC column on the google sheet?
#Override
protected void onActivityResult ( int requestCode, int resultCode, Intent data){
IntentResult result = IntentIntegrator.parseActivityResult(requestCode, resultCode, data);
if (result != null) {
if (result.getContents() == null) {
Log.d("MainActivity", "Cancelled scan");
Toast.makeText(this, "Cancelled", Toast.LENGTH_LONG).show();
} else {
Log.d("MainActivity", "Scanned");
Toast.makeText(this, "Scanned: " + result.getContents(), Toast.LENGTH_LONG).show();
}
} else {
super.onActivityResult(requestCode, resultCode, data);
I want to show this code as a "Yes" or "NO" based on if the scanned barcode is already in the spreadsheet. My question is how to get the spreadsheet to communicate with the scanner or can copy all of the barcodes from the spreadsheet in a boolean?
Set<String> getStringSet (String key,
Set<String> defValues)
makeText(Context context, int resId, int duration)
protected void onActivityResult ( int requestCode, int resultCode, Intent data){
IntentResult result = IntentIntegrator.parseActivityResult(requestCode, resultCode, data);
if (result != null) {
if (result.getContents() == null) {
Log.d("MainActivity", "Cancelled scan");
Toast.makeText(this, "Cancelled", Toast.LENGTH_LONG).show();
} else {
Log.d("MainActivity", "Scanned");
Toast.makeText(this, "Scanned: " + result.getContents(), Toast.LENGTH_LONG).show();
}
So above is what ive come up with from search. Is it practical to use shared preference to store my data(1000 UPC) use ZXING to parse as well as IF ELSE to check the code and finally TOAST to show "YES" or "NO" based on if my result is located in the shared preference?
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button button = this.findViewById(R.id.button);
final Activity activity = this;
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
IntentIntegrator integrator = new IntentIntegrator(activity);
integrator.setDesiredBarcodeFormats(IntentIntegrator.ALL_CODE_TYPES);
integrator.setPrompt("Scan");
integrator.setCameraId(0);
integrator.setBeepEnabled(false);
integrator.setBarcodeImageEnabled(false);
integrator.initiateScan();
}
});
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
IntentResult result = IntentIntegrator.parseActivityResult(requestCode, resultCode, data);
if (result != null) {
if (result.getContents() == null) {
Log.d("MainActivity", "Cancelled scan");
Toast.makeText(this, "Cancelled", Toast.LENGTH_LONG).show();
} else {
Log.d("MainActivity", "Scanned");
Toast.makeText(this, "Scanned: " + result.getContents(), Toast.LENGTH_LONG).show();
}
} else {
super.onActivityResult(requestCode, resultCode, data);
}
}
public void scanCode(View view) {
}
public class myWebView extends MainActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
WebView webview = new WebView(this);
setContentView(webview);
WebView myWebView = findViewById(R.id.myWebView);
myWebView.setWebViewClient(new MyWebViewClient());
WebSettings webSettings = myWebView.getSettings();
webSettings.setJavaScriptEnabled(true);
webview.loadUrl("https://google.com/");
}
private class MyWebViewClient extends WebViewClient {
#Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
startActivity(intent);
return true;
}
}
}
}
for segregation of code you need to create SacnActivity as a separate activity which is extend Activity and impliments ZXingScannerView.ResultHandler and call from the MainActivity and give call back to Mainactivity in onActivityResult().
MainActivity
public class MainActivity extends Activity{
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
scan = (Button)findViewById(R.id.btnScan);
scan.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
startActivityForResult(new Intent(MainActivity.this,SacnActivity .class),1);
}
});
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == 1) {
if(resultCode == Activity.RESULT_OK){
String result=data.getStringExtra("result");
Log.d("result================>",""+result);
try {
//processData(result);
} catch (Exception e) {
e.printStackTrace();
}
}
if (resultCode == Activity.RESULT_CANCELED) {

How to use in-built voice recognition in my Android app?

I want to use offline voice recognition in my app.
Setting -> “Language and Input” -> "Google Voice Typing" -> "Offline speech recognition" :- I would like to use this built-in feature.
In the below code, I tried to implement it using Recognizer Intent, but it uses the Google voice search (works online). Please help.
public class MainActivity extends AppCompatActivity {
private TextView txtSpeechInput;
private ImageButton btnSpeak;
private final int REQ_CODE_SPEECH_INPUT = 100;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
promptSpeechInput();
//onCreateOptionsMenu();
}
private void promptSpeechInput() {
Intent intent = new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH);
intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL,
RecognizerIntent.LANGUAGE_MODEL_FREE_FORM);
intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE, Locale.getDefault());
intent.putExtra(RecognizerIntent.EXTRA_PROMPT,
getString(R.string.speech_prompt));
try {
startActivityForResult(intent, REQ_CODE_SPEECH_INPUT);
} catch (ActivityNotFoundException a) {
Toast.makeText(getApplicationContext(),
getString(R.string.speech_not_supported),
Toast.LENGTH_SHORT).show();
}
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
switch (requestCode) {
case REQ_CODE_SPEECH_INPUT: {
if (resultCode == RESULT_OK && null != data) {
ArrayList<String> result = data
.getStringArrayListExtra(RecognizerIntent.EXTRA_RESULTS);
//txtSpeechInput.setText(result.get(0));
{
String a="camera";
if(a.compareTo(result.get(0))==0){
Intent i = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
if (i.resolveActivity(getPackageManager()) != null) {
startActivityForResult(i, 1);
}
}
}
}
break;
}
}
}
Well, here I am sending intent to camera via voice. So, I have a limited vocabulary requirement here.
Try this:
intent.putExtra(RecognizerIntent.EXTRA_PREFER_OFFLINE,true);
Note: This will work only on API level 23 and above.

Very hard object-oriented "transplantation"in android

In my android app there are at least 4 places where the user can click a photo and then get a dialog saying "take a photo or pick from gallery to change your picture"
in each of these places its a different activity with different variables and different xml element names and I have a lot of really similar code, repeated through out my app.
I want to take it out in a separate class, but is so tangled up in the code that it feels like a heart transplantation. My object-oriented skills and Java skills arent that great (3 months experience) and maybe there is some workaround in Android that I dont know about.
I will provide two examples from different classes so you get an idea of how much repetition there is. I will be very grateful if someone could help me produce a separate object out of this
Settings class, image changer excerpt:
iUserAvatarSettings.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
final Dialog dialog = new Dialog(Settings.this, R.style.no_title_dialog);
if (!userHasProvidedOwnPhoto) {
dialog.setContentView(R.layout.signup_avatar_upload_dialog);
} else {
dialog.setContentView(R.layout.signup_avatar_upload_dialog_2);
bDeleteAvatar = (Button) dialog.findViewById(R.id.bDeleteAvatar);
try {
bDeleteAvatar.setTypeface(font1);
} catch (Exception e) {
}
bDeleteAvatar.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
setAvatarPath("default_avatar");
userHasProvidedOwnPhoto = false;
if (userSex.equals("Male") || userSex.equals("")) {
iUserAvatarSettings.setImageResource(R.drawable.avatar_default_male);
} else {
iUserAvatarSettings.setImageResource(R.drawable.avatar_default_female);
}
dialog.dismiss();
}
});
}
Button bTakeAPhoto = (Button) dialog.findViewById(R.id.bTakeAPhoto);
Button bSelectPhotoFromFile = (Button) dialog.findViewById(R.id.bSelectPhotoFromFile);
Button bCancelAvatarUpload = (Button) dialog.findViewById(R.id.bCancelAvatarUpload);
try {
bTakeAPhoto.setTypeface(font1);
bSelectPhotoFromFile.setTypeface(font1);
bCancelAvatarUpload.setTypeface(font1);
} catch (Exception e) {
}
bTakeAPhoto.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
if (isIntentAvailable(Settings.this, MediaStore.ACTION_IMAGE_CAPTURE)) {
Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
startActivityForResult(takePictureIntent, TAKE_IMAGE_WITH_CAMERA);
dialog.dismiss();
} else {
toastMaker.toast(net.asdqwe.activities.Settings.this, Configurationz.ErrorMessages.DEVICE_UNABLE_TO_TAKE_PHOTOS, Toast.LENGTH_LONG);
dialog.dismiss();
userHasProvidedOwnPhoto = false;
}
}
});
bSelectPhotoFromFile.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
Intent getImageFromGallery = new Intent(Intent.ACTION_PICK, android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
getImageFromGallery.setType("image/*");
startActivityForResult(getImageFromGallery, PICK_IMAGE);
//avatarPath = saveUserAvatar.getUserAvatar().toString();
//setAvatarPath(saveUserAvatar.getUserAvatar().toString()); // this remains under question
dialog.dismiss();
}
});
bCancelAvatarUpload.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
dialog.dismiss();
}
});
dialog.show();
}
}); // end of image button on click handling
public static boolean isIntentAvailable(Context context, String action) {
final PackageManager packageManager = context.getPackageManager();
final Intent intent = new Intent(action);
List<ResolveInfo> list = packageManager.queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY);
return list.size() > 0;
}
private void handleSmallCameraPhoto(Intent intent) {
try {
Bundle extras = intent.getExtras();
mImageBitmap = (Bitmap) extras.get("data");
iUserAvatarSettings.setImageBitmap(mImageBitmap);
saveUserAvatar.SaveImage(this, mImageBitmap);
userHasProvidedOwnPhoto = true;
setAvatarPath(saveUserAvatar.getUserAvatar().toString());
} catch (Exception e) {
toastMaker.toast(net.asdqwe.activities.Settings.this, Configurationz.ErrorMessages.TAKING_PHOTO_FAILED, Toast.LENGTH_LONG);
userHasProvidedOwnPhoto = false;
}
}
private void handleGalleryPhoto(Intent intent) {
try {
Uri _uri = intent.getData();
Cursor cursor = getContentResolver().query(_uri, new String[] { android.provider.MediaStore.Images.ImageColumns.DATA }, null, null, null);
cursor.moveToFirst();
final String imageFilePath = cursor.getString(0);
cursor.close();
mImageBitmap2 = BitmapFactory.decodeFile(imageFilePath);
iUserAvatarSettings.setImageBitmap(mImageBitmap2);
saveUserAvatar.SaveImage(this, mImageBitmap2);
userHasProvidedOwnPhoto = true;
setAvatarPath(saveUserAvatar.getUserAvatar().toString());
} catch (Exception e) {
toastMaker.toast(net.zxcasd.activities.Settings.this, Configurationz.ErrorMessages.PICKING_PHOTO_FROM_GALLERY_FAILED, Toast.LENGTH_LONG);
userHasProvidedOwnPhoto = false;
}
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == TAKE_IMAGE_WITH_CAMERA && resultCode == RESULT_OK && null != data) {
handleSmallCameraPhoto(data);
} else if (requestCode == PICK_IMAGE && resultCode == RESULT_OK && null != data) {
handleGalleryPhoto(data);
}
}
Signup class, image excerpt:
iUserAvatar.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
final Dialog dialog = new Dialog(Signup.this, R.style.no_title_dialog);
if (!userHasProvidedOwnPhoto) {
dialog.setContentView(R.layout.signup_avatar_upload_dialog);
} else {
dialog.setContentView(R.layout.signup_avatar_upload_dialog_2);
bDeleteAvatar = (Button) dialog.findViewById(R.id.bDeleteAvatar);
try {
bDeleteAvatar.setTypeface(font1);
} catch (Exception e) {
}
bDeleteAvatar.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
userHasProvidedOwnPhoto = false;
if (userSex.equals("Male") || userSex.equals("")) {
iUserAvatar.setImageResource(R.drawable.avatar_default_male);
} else {
iUserAvatar.setImageResource(R.drawable.avatar_default_female);
}
dialog.dismiss();
}
});
}
Button bTakeAPhotoSignupPage = (Button) dialog.findViewById(R.id.bTakeAPhoto);
Button bSelectPhotoFromFileSignupPage = (Button) dialog.findViewById(R.id.bSelectPhotoFromFile);
Button bCancelAvatarUpload = (Button) dialog.findViewById(R.id.bCancelAvatarUpload);
try {
bTakeAPhotoSignupPage.setTypeface(font1);
bSelectPhotoFromFileSignupPage.setTypeface(font1);
bCancelAvatarUpload.setTypeface(font1);
} catch (Exception e) {
}
bTakeAPhotoSignupPage.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
if (isIntentAvailable(Signup.this, MediaStore.ACTION_IMAGE_CAPTURE)) {
Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
startActivityForResult(takePictureIntent, TAKE_IMAGE_WITH_CAMERA);
dialog.dismiss();
} else {
toastMaker.toast(net.asdqwe.activities.Signup.this, Configurationz.ErrorMessages.DEVICE_UNABLE_TO_TAKE_PHOTOS, Toast.LENGTH_LONG);
dialog.dismiss();
userHasProvidedOwnPhoto = false;
}
}
});
bSelectPhotoFromFileSignupPage.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
Intent getImageFromGallery = new Intent(Intent.ACTION_PICK, android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
getImageFromGallery.setType("image/*");
startActivityForResult(getImageFromGallery, PICK_IMAGE);
dialog.dismiss();
}
});
bCancelAvatarUpload.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
// and deal with photo
dialog.dismiss();
}
});
dialog.show();
}
});
public static boolean isIntentAvailable(Context context, String action) {
final PackageManager packageManager = context.getPackageManager();
final Intent intent = new Intent(action);
List<ResolveInfo> list = packageManager.queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY);
return list.size() > 0;
}
private void handleSmallCameraPhoto(Intent intent) {
try {
Bundle extras = intent.getExtras();
mImageBitmap = (Bitmap) extras.get("data");
iUserAvatar.setImageBitmap(mImageBitmap);
saveUserAvatar.SaveImage(this, mImageBitmap);
userHasProvidedOwnPhoto = true;
} catch (Exception e) {
toastMaker.toast(net.asdqwe.activities.Signup.this, Configurationz.ErrorMessages.TAKING_PHOTO_FAILED, Toast.LENGTH_LONG);
userHasProvidedOwnPhoto = false;
}
}
private void handleGalleryPhoto(Intent intent) {
try {
Uri _uri = intent.getData();
Cursor cursor = getContentResolver().query(_uri, new String[] { android.provider.MediaStore.Images.ImageColumns.DATA }, null, null, null);
cursor.moveToFirst();
final String imageFilePath = cursor.getString(0);
cursor.close();
mImageBitmap2 = BitmapFactory.decodeFile(imageFilePath);
iUserAvatar.setImageBitmap(mImageBitmap2);
saveUserAvatar.SaveImage(this, mImageBitmap2);
userHasProvidedOwnPhoto = true;
} catch (Exception e) {
toastMaker.toast(net.asdqwe.activities.Signup.this, Configurationz.ErrorMessages.PICKING_PHOTO_FROM_GALLERY_FAILED, Toast.LENGTH_LONG);
userHasProvidedOwnPhoto = false;
}
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == TAKE_IMAGE_WITH_CAMERA && resultCode == RESULT_OK && null != data) {
handleSmallCameraPhoto(data);
} else if (requestCode == PICK_IMAGE && resultCode == RESULT_OK && null != data) {
handleGalleryPhoto(data);
}
}
Move isIntentAvailable(Context, String) into an utility class. This could be helpful in some other uses cases.
Create a abstract class (refered to as MyAbstractActivity) which contains all common activity methods: handleSmallCameraPhoto(Intent), handleGalleryPhoto(Intent) and onActivityResult(int, int, Intent)
iUserAvatarSettings / iUserAvatar must be part of MyAbstractActivity. If you need different implementations of it for different use cases, create an abstract getter, f.e. getUserAvatarButton().
setAvatarPath(String) is only used in one of the two classes. Make it an abstract method in MyAbstractActivity and implement it as needed.
Let the other classes inherit from MyAbstractActivity.
Transform the OnClickListener into a class.
As constructor arguments you pass a subclass of MyAbstractActivity and a Button (iUserAvatarSettings / iUserAvatar).
Use the constructor arguments to refer to methods and variables like userHasProvidedOwnPhoto.
The iUserAvatar.setOnClickListener(...) part will remain in MyAbstractActivity.
Now you have removed the code redundancy, but there will be more to do. Probably encapsulation isn't good enough right now.
Think about moving methods and variables to the OnClickListener class or away from it.
Think about moving methods and variables to MyAbstractActivity or away from it.
Ask some more experienced developer to make a review. (Don't ask him to refactor it.)
If you have specific refactoring question come back her and ask the community.
You can check my project Android Image Helper on Github
An activity with image selection feature would look something like this:
public class ImageUploaderActivity extends Activity implements ImageChooseCallback {
ImageUploadEngine uploadEngine;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
uploadEngine = new ImageUploadEngine.Builder(this, savedInstanceState).build();
//...
someButton.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
uploadEngine.performImageAsk(R.string.app_name, R.string.newphoto, R.string.oldphoto, R.string.choose, R.drawable.ic_launcher);
}
});
}
#Override
public void onSaveInstanceState(Bundle outState) {
uploadEngine.onSaveInstanceState(outState);
}
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if(uploadEngine.onActivityResult(requestCode, resultCode, data)) return;
super.onActivityResult(requestCode, resultCode, data);
}
#Override
public void onCanceled(ImageUploadEngine engine) {
//notifying you that the user has canceled the request
}
#Override
public void onChosen(ImageUploadEngine engine, String path, boolean newPicture) {
//notifying you that the user has selected an image
}
#Override
public void onError(ImageUploadEngine engine, Exception ex) {
//notifying you that an error has occurred
}
}
The uploadEngine also exposes functions performImageTake and performImageChoose in case the default dialog (to choose) does not suit your needs.
FYI:
This project aims to provide an easy-to-use instrument for android developers to use when they need the user to select an image on their android phone and upload it. If the process has any errors on specific phones, these should be handled inside the library to provide the same user experience on all phones.
Here is my approach to refactor your code. I have tried to give some justification about my design as well.
1) You could abstract away the dialog into a widget.
You can create a PhotoPickerDialog that extends Dialog and provides desired functionality. Then you can re-use this widget at different places / activities.
public class PhotoPickerDialog extends Dialog {
//private fields
private Typeface buttonFont = Typeface.DEFAULT;
private Button bTakeAPhoto;
private Button bSelectPhotoFromFile;
private Button bCancelAvatarUpload;
private IMediaHelper mMediaHelper;
public PhotoPickerDialog(Context context) {
super(context);
initView();
}
public PhotoPickerDialog(Context context, int theme) {
super(context, theme);
initView();
}
protected PhotoPickerDialog(Context context, boolean cancelable, OnCancelListener cancelListener) {
super(context, cancelable, cancelListener);
initView();
}
protected void setLayoutResource() {
setContentView(R.layout.signup_avatar_upload_dialog);
}
protected void initView() {
setLayoutResource();
bTakeAPhoto = (Button) findViewById(R.id.bTakeAPhoto);
bSelectPhotoFromFile = (Button) findViewById(R.id.bSelectPhotoFromFile);
bCancelAvatarUpload = (Button) findViewById(R.id.bCancelAvatarUpload);
bCancelAvatarUpload.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
dismiss();
}
});
}
/**
* Set the type face of the button, in case you want to have different
* font at different times.
*/
public void setButtonFont(Typeface font) {
buttonFont = font;
bTakeAPhoto.setTypeface(buttonFont);
bSelectPhotoFromFile.setTypeface(buttonFont);
bCancelAvatarUpload.setTypeface(buttonFont);
}
/**
* Set the media helper object which implements the functionality to
* take and pick photo. So the task delegated to this media helper.
*/
public void setMediaHelper(IMediaHelper mediaHelper) {
mMediaHelper = mediaHelper;
bTakeAPhoto.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
mMediaHelper.takePhoto();
dismiss();
}
});
bSelectPhotoFromFile.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
mMediaHelper.pickPhoto();
dismiss();
}
});
}
}
Since you need two different types of dialogs depending on whether the user has a avatar photo already or not. Let us create a PhotoPickerDialogWithDelete that extends PhotoPickerDialog. Then we just have to override a few methods and add the delete callback to make our new type of dialog without re-writing a lot of code.
public class PhotoPickerDialogWithDelete extends PhotoPickerDialog {
private Button bDeleteAvatar;
public PhotoPickerDialogWithDelete(Context context) {
super(context);
}
public PhotoPickerDialogWithDelete(Context context, int theme) {
super(context, theme);
}
protected PhotoPickerDialogWithDelete(Context context, boolean cancelable, OnCancelListener cancelListener) {
super(context, cancelable, cancelListener);
}
#Override
protected void setLayoutResource() {
setContentView(R.layout.signup_avatar_upload_dialog_2);
}
#Override
protected void initView() {
super.initView();
bDeleteAvatar = (Button) findViewById(R.id.bDeleteAvatar);
}
#Override
public void setButtonFont(Typeface font) {
super.setButtonFont(font);
bDeleteAvatar.setTypeface(font);
}
public void setOnDeleteListener(final View.OnClickListener listener) {
bDeleteAvatar.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
dismiss();
listener.onClick(v);
}
});
}
}
2) Move the photo intent related functionality to an abstract base class MediaSupportActivity.
All the activities that need to support taking/picking photos just need to extend from this class and implement two simple methods handleSmallCameraPhoto(Bitmap) and handleGalleryPhoto(Bitmap). They do not have to explicitly care about how to take/pick photos, but only care about how to handle them (which can be different for different activities).
public abstract class MediaSupportActivity extends Activity implements IMediaHelper {
private static final int TAKE_IMAGE_WITH_CAMERA = 1;
private static final int PICK_IMAGE = 2;
protected abstract void handleSmallCameraPhoto(Bitmap image);
protected abstract void handleGalleryPhoto(Bitmap image);
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == TAKE_IMAGE_WITH_CAMERA && resultCode == RESULT_OK && null != data) {
Bundle extras = data.getExtras();
Bitmap bitmap = (Bitmap) extras.get("data");
handleSmallCameraPhoto(bitmap);
}
else if (requestCode == PICK_IMAGE && resultCode == RESULT_OK && null != data) {
Uri _uri = data.getData();
Cursor cursor = getContentResolver().query(_uri, new String[] { android.provider.MediaStore.Images.ImageColumns.DATA }, null, null, null);
cursor.moveToFirst();
final String imageFilePath = cursor.getString(0);
cursor.close();
Bitmap bitmap = BitmapFactory.decodeFile(imageFilePath);
handleGalleryPhoto(bitmap);
}
}
#Override
public void takePhoto() {
Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
startActivityForResult(takePictureIntent, MediaSupportActivity.TAKE_IMAGE_WITH_CAMERA);
}
#Override
public void pickPhoto() {
Intent getImageFromGallery = new Intent(Intent.ACTION_PICK, android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
getImageFromGallery.setType("image/*");
startActivityForResult(getImageFromGallery, MediaSupportActivity.PICK_IMAGE);
}
}
3) There is an interface IBBMediaHelper that defined two methods: takePhoto() and pickPhoto(). We pass a IBBMediaHelper instance to the dialog, so that that dialog does not have full access to the other properties and methods of the MediaSupportActivity
public interface IMediaHelper {
public void takePhoto();
public void pickPhoto();
}
4) Here is a sample how to use the above classes together:
public class MainActivity extends MediaSupportActivity {
Button iUserAvatarSettings;
private boolean userHasProvidedOwnPhoto = false;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
iUserAvatarSettings = (Button) findViewById(R.id.button);
iUserAvatarSettings.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
final PhotoPickerDialog dialog;
if (!userHasProvidedOwnPhoto) {
dialog = new PhotoPickerDialog(MainActivity.this);
}
else {
dialog = new PhotoPickerDialogWithDelete(MainActivity.this);
((PhotoPickerDialogWithDelete)dialog).setOnDeleteListener(onAvatarDelete);
}
dialog.setButtonFont(Typeface.MONOSPACE);
dialog.setMediaHelper(MainActivity.this);
dialog.show();
}
});
}
#Override
protected void handleSmallCameraPhoto(Bitmap image) {
// sample code
ImageView imageView = (ImageView) findViewById(R.id.imageView);
imageView.setImageBitmap(image);
}
#Override
protected void handleGalleryPhoto(Bitmap image) {
// sample code
ImageView imageView = (ImageView) findViewById(R.id.imageView);
imageView.setImageBitmap(image);
}
private OnClickListener onAvatarDelete = new OnClickListener() {
#Override
public void onClick(View v) {
// this is executed when delete is clicked
// check for male/female and update the avatar
// etc. etc.
}
};
}
Update: You can also create an avatar widget AvatarWidget class that contains an ImageView and PhotoPickerDialog. This class encapsulates the logic of displaying an avatar, clicking on it to show the menu and setting the default avatar when delete is clicked. Then in the main activity, simply declare your avatar widget via code or XML and call the setters on it when the image is received.

Categories