On my MapActivity, when you tap on an ItemizedOverlay, it displays the
Title
Snippet / Messsage in a TextView and changes each time another ItemizedOverlay is clicked or tapped
I have created an ImageButton with a phone image on it and i am trying to call an Array Intent to it
So basically, when Users Tap on Overlay1, and then decide to tap on the Phone Image Button the number stored in the intent, changes to Overlay1's number and so they can call Overlay 1
and if they tap on Overlay 2, then the number would change accordingly etc
my Code is as follows:
List<Overlay> mapOverlays;
List<Intent> mapIntents;
NewItemizedOverlay itemizedOverlay;
Intent intentCall;
GeoPoint point = new GeoPoint((int)(51.555890943494276*1E6), (int)(-0.39989858865737915*1E6));
OverlayItem overlayitem = new OverlayItem(point, "Greenwood Veterinary" , "57 Station Approach, South Ruislip, Ruislip, Middlesex, HA4 6SL, 020 8845 8144");
itemizedOverlay.addOverlay(overlayitem);
Intent vet1 = new Intent(android.content.Intent.ACTION_DIAL,Uri.parse("tel:020 8845 8144")); // i created this in a similar fashion to the itemizedOverlay
intentCall.?(vet1); // i wanted to try and do the same thing with the addOverlay but i cant seem to find the correct method of doing this
GeoPoint point2 = new GeoPoint((int)(51.598707*1E6), (int)(-0.393416*1E6));
OverlayItem overlayitem2 = new OverlayItem(point2, "MediVet Pinner" , "2A Pinner Green, Pinner, Middlesex, HA5 2AA, 020 8866 0727");
itemizedOverlay.addOverlay(overlayitem2);
Intent vet2 = new Intent(android.content.Intent.ACTION_DIAL,Uri.parse("tel:020 8866 0727"));
ItemizedOverlay:
private ArrayList<OverlayItem> mOverlays = new ArrayList<OverlayItem>();
private ArrayList<Intent> cIntents = new ArrayList<Intent>();
Context mContext;
public NewItemizedOverlay(Drawable defaultMarker) {
super(boundCenterBottom(defaultMarker));
}
public NewItemizedOverlay(Drawable defaultMarker, Context context)
{
super(boundCenterBottom(defaultMarker));
mContext = context;
}
public void addOverlay(OverlayItem overlay)
{
mOverlays.add(overlay);
populate();
}
public void addOverlay(OverlayItem overlay, Intent intent)
{
mOverlays.add(overlay);
cIntents.add(intent);
populate();
}
#Override
protected OverlayItem createItem(int i) {
// TODO Auto-generated method stub
return mOverlays.get(i);
}
protected Intent createCall(int c)
{
return cIntents.get(c);
}
#Override
public int size() {
// TODO Auto-generated method stub
return mOverlays.size();
}
public int callsize()
{
return cIntents.size();
}
#Override
protected boolean onTap(int index) {
OverlayItem item = mOverlays.get(index);
Intent callItem = cIntents.get(index);
AlertDialog.Builder dialog = new AlertDialog.Builder(mContext);
dialog.setIcon(android.R.drawable.ic_dialog_info);
dialog.setTitle(item.getTitle());
dialog.setMessage(item.getSnippet());
dialog.setPositiveButton("OK", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
// TODO Auto-generated method stub
}
});
dialog.setNeutralButton("Call", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
// TODO Auto-generated method stub
VetNumber. //Not sure how to exactly call the Intent
}
});
dialog.show();
return true;
}
}
If anyone could help, i would be very grateful
Thank You
Maybe it's too late for you, but you can start a new intent if you know the context where you are. If you're working with MapActivity and ItemizedOverlay you can get the context in LocalizacionItemizedOverlay.
Context mContext;
public LocalizacionItemizedOverlay(Drawable defaultMarker, Context context) {
super(boundCenterBottom(defaultMarker));
mContext=context;
}
Then in the onTap function you can write some similar to:
dialog.setPositiveButton("Ver", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
Intent nextScreen = new Intent(mContext, YourActivity.class); //define the intent
nextScreen.putExtra("definicionURL",definicion.url); //pass variables
mContext.startActivity(nextScreen); //launch the intent
}
});
This has been my first post in stackoverflow.com and I want to say something to all people posting solutions here: thank you very much.
Related
I have 2 activities. In the first one i choose a level. In the second i play the game.In the second activity I answer questions and everytime I answer correctly I add one value to my arraylist. When the game ends a user goes back to level select activity and there he can see his score. For example: Level1: you answered 17 questions correctly. How can I achieve that? I tried using sharedpreferences but had no luck. It always shows 0. Im guessing its because it gets the value at the start of the game, when the list is empty. How to show the values after the game has ended when the list is filled?
This is the game activity in witch I create a list, store values in it and answer questions.:
public class MainActivity extends Activity {
Button mYes;
Button mNo;
TextView mQuestion;
Button btnClosePopup;
TextView mPopupText;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final int[] count = {0}; // Global array.
final int[] score = {0};
//final int[] intArray = new int[3];
mYes = (Button) findViewById(R.id.button2);
mPopupText = (TextView)findViewById(R.id.popupTekstas);
btnClosePopup = (Button)findViewById(R.id.btn_close_popup);
mNo = (Button) findViewById(R.id.button);
mQuestion = (TextView) findViewById(R.id.textView);
//Creating questions. (Question, boolean, answer).
final Question first = new Question("Do i understand this code?", true, "Only Jesus knows");
final Question second = new Question("Why dont i understand this code?", false, "Im not Jesus");
final Question third = new Question("Why I am not Jesus?", true, "2fat.");
//Creating Lists for questions and boolean values.
final ArrayList<Question> questions = new ArrayList<Question>();
final ArrayList<Boolean> type = new ArrayList<Boolean>();
final ArrayList<Integer> points = new ArrayList<Integer>();
SharedPreferences sharedPref = getSharedPreferences("level1", Context.MODE_PRIVATE);
SharedPreferences.Editor editor = sharedPref.edit();
editor.putInt("taskai", points.size());
editor.commit();
//mResult.setText("zdr");
//Adding questions to the question list
questions.add(first);
questions.add(second);
questions.add(third);
// Adding boleans to the boolean list
type.add(first.correctAnswer);
type.add(second.correctAnswer);
type.add(third.correctAnswer);
//Show the first question on Activity start.
mQuestion.setText(questions.get(0).question);
// Open PopUp Window on true button click.
mYes.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
initiatePopupWindow();
if(type.get(count[0])){
((TextView)pwindo.getContentView().findViewById(R.id.popupTekstasTiesaArNe)).setText("Correct!");
} else {
((TextView)pwindo.getContentView().findViewById(R.id.popupTekstasTiesaArNe)).setText("False!");
}
//Show the first answer on first button click.
((TextView)pwindo.getContentView().findViewById(R.id.popupTekstas)).setText(questions.get((count[0]) % questions.size()).answer);
// When PopUp button closes open the next question with the if/else conditions.
btnClosePopup.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
//if the question is true show next question/ else close app
if (type.get(count[0])) {
points.add(1); // if the answer is correct add +1 to the list.
score[0]++;
if(questions.size()-1 == count[0]) // if you count[0] is init to 0
{
AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this);
builder.setTitle("WInner");
builder.setMessage("You won, play again?");
builder.setCancelable(false);
builder.setPositiveButton(android.R.string.yes,
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
// just close dialog
dialog.cancel();
}
});
builder.setNegativeButton(android.R.string.no,
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
finish();
// mResult.setText("" + points.size());
}
});
// Create dialog from builder
AlertDialog alert = builder.create();
// Show dialog
alert.show();
count[0]=0;
}
else if(questions.size()-1 < count[0])
try {
throw new Exception("Invalid ");
} catch (Exception e) {
e.printStackTrace();
}
else
count[0]++;
mQuestion.setText(questions.get(count[0]).question); // you dont need calculate the module anymore
pwindo.dismiss();
} else {
count[0]++;
mQuestion.setText(questions.get(count[0]).question); // you dont need calculate the module anymore
pwindo.dismiss();
}
}
});
}
});
mNo.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
initiatePopupWindow();
if(!type.get(count[0])){
((TextView)pwindo.getContentView().findViewById(R.id.popupTekstasTiesaArNe)).setText("Correct!");
} else {
((TextView)pwindo.getContentView().findViewById(R.id.popupTekstasTiesaArNe)).setText("False!");
}
((TextView)pwindo.getContentView().findViewById(R.id.popupTekstas)).setText(questions.get((count[0]) % questions.size()).answer);
btnClosePopup.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (!type.get(count[0])) {
points.add(1); // if the answer is correct add +1 to the list.
score[0]++;
if(questions.size()-1 == count[0]) // if you count[0] is init to 0
{
AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this);
builder.setTitle("WInner")
.setMessage("You won, play again?")
.setCancelable(false)
.setPositiveButton(android.R.string.yes,
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
// just close dialog
dialog.cancel();
}
})
.setNegativeButton(android.R.string.no,
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
finish();
//mResult.setText("" + points.size());
}
});
// Create dialog from builder
AlertDialog alert = builder.create();
// Show dialog
alert.show();
count[0]=0;
((TextView)pwindo.getContentView().findViewById(R.id.popupTekstasTiesaArNe)).setText("Klaida!");
}
else if(questions.size()-1 < count[0])
try {
throw new Exception("Invalid ");
} catch (Exception e) {
e.printStackTrace();
}
else
count[0]++;
mQuestion.setText(questions.get(count[0]).question); // you dont need calculate the module anymore
pwindo.dismiss();
} else {
count[0]++;
mQuestion.setText(questions.get(count[0]).question); // you dont need calculate the module anymore
pwindo.dismiss();
}
}
});
}
});
}
public PopupWindow pwindo;
public void initiatePopupWindow() {
try {
// We need to get the instance of the LayoutInflater
LayoutInflater inflater = (LayoutInflater) MainActivity.this
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View layout = inflater.inflate(R.layout.popup,
(ViewGroup) findViewById(R.id.popup_element));
pwindo = new PopupWindow(layout, 500, 570, true);
pwindo.showAtLocation(layout, Gravity.CENTER, 0, 0);
btnClosePopup = (Button) layout.findViewById(R.id.btn_close_popup);
btnClosePopup.setOnClickListener(cancel_button_click_listener);
} catch (Exception e) {
e.printStackTrace();
}
}
public View.OnClickListener cancel_button_click_listener = new View.OnClickListener() {
#Override
public void onClick(View v) {
pwindo.dismiss();
}
};
In this activity I try to get the list values and show them:
public class LevelSelectActivity extends MainActivity {
Button mLevel1;
public TextView mResult;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_level_select);
SharedPreferences sharedPref = getSharedPreferences("level1", Context.MODE_PRIVATE);
int result = sharedPref.getInt("taskai", 0);
mLevel1 = (Button)findViewById(R.id.level1);
mResult = (TextView)findViewById(R.id.Resultas);
// mResult.setText(players.size()-1 + "/" + 3);
mResult.setText("" + result);
mLevel1.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent startGame = new Intent(LevelSelectActivity.this, MainActivity.class);
startActivity(startGame);
}
});
}
I don't know for sure what's happening in your code, but I do know preferences aren't the best way to pass data.
You are better off using a set results/ get results pattern.
The first activity uses
startActivityForResult(intent, LEVEL_REQUEST);
It will also create a function to read back the data after it is done. That'll look something like:
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
// Check which request we're responding to
if (requestCode == LEVEL_REQUEST) {
// Make sure the request was successful
if (resultCode == RESULT_OK) {
}
}
}
The activity sending the results will do this to publish the results:
Intent resultsIntent=new Intent();
//Set data in the intent, note this intent is returned to the original function in `onActivityResult`
setResult(Activity.RESULT_OK,resultsIntent);
The second activity uses
The following is the service class of my music player, the implemented onPrepared() method is never called, so I have to use setOnPreparedListener to get the things done.
I want to execute it from the unimplemented section.
public class MusicService extends Service implements MediaPlayer.OnPreparedListener,
MediaPlayer.OnErrorListener,MediaPlayer.OnCompletionListener {
//media player
private MediaPlayer player;
//song list
private ArrayList<Song> songs;
//current position
private int songPosn;
private String songTitle="";
private static final int NOTIFY_ID=1;
private final IBinder musicBind = new MusicBinder();
#Override
public IBinder onBind(Intent intent) {
return musicBind;
}
public boolean onUnbind(Intent intent){
player.stop();
player.release();
return false;
}
#Override
public void onCreate() {
// TODO Auto-generated method stub
super.onCreate();
//initialize position
songPosn = 0;
//create player
player = new MediaPlayer();
}
#Override
public void onCompletion(MediaPlayer mp) {
// TODO Auto-generated method stub
}
#Override
public boolean onError(MediaPlayer mp, int what, int extra) {
// TODO Auto-generated method stub
return false;
}
//this is never being called and instead of this the one in setOnPreparedListener is called
#Override
public void onPrepared(MediaPlayer mp) {
// TODO Auto-generated method stub
//start music
mp.start();
Intent notIntent = new Intent(this, MainActivity.class);
notIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
PendingIntent pendInt = PendingIntent.getActivity(this, 0, notIntent, PendingIntent.FLAG_UPDATE_CURRENT);
NotificationCompat.Builder builder = new NotificationCompat.Builder(this);
builder.setContentIntent(pendInt)
.setSmallIcon(R.drawable.play)
.setTicker(songTitle)
.setOngoing(true)
.setContentText("Playing")
.setContentText(songTitle);
Notification not = builder.build();
startForeground(NOTIFY_ID, not);
}
public void initMusicPlayer(){
//set player properties
player.setWakeMode(getApplicationContext(), PowerManager.PARTIAL_WAKE_LOCK);
player.setAudioStreamType(AudioManager.STREAM_MUSIC);
}
public void setSong(int songIndex){
songPosn=songIndex;
}
public void setList(ArrayList<Song> theSongs){
songs = theSongs;
}
public void playSong(){
//play a cool song
player.reset();
//get song
Song playSong = songs.get(songPosn);
songTitle = playSong.getTitle();
//get ID
long currSong = playSong.getId();
//set path to sdcard or squaremash server
Uri trackUri = ContentUris.withAppendedId(android.provider.MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, currSong);
try {
player.setDataSource(getApplicationContext(), trackUri);
} catch (Exception e) {
Log.e("Music service","Error: setting data source",e); }
player.prepareAsync();
//this one is called, If I remove this, the above onPrepared method isnt called
player.setOnPreparedListener(new OnPreparedListener() {
#Override
public void onPrepared(MediaPlayer mp) {
// TODO Auto-generated method stub
mp.start();
}
});
}
public void go(){
player.start();
}
//previous song
public void playPrev() {
songPosn--;
if(songPosn<0)
songPosn=songs.size()-1;
playSong();
}
//next song
public void playNext() {
songPosn++;
if(songPosn>=songs.size())
songPosn=0;
playSong();
}
}
This is not how Java works.
You're extending a Service object. There is nothing in that object's lifecycle that triggeres a call to onPrepared(). What triggers that call is your player member:
private MediaPlayer player;
And for that to happen, i.e. for player to trigger a call to onPrepared(), you need to point it to an object implementing onPrepared(). This object is your MusicService object, thus you need to call:
player.setOnPreparedListener(this);
You don't set the correct OnPreparedListener.
In onCreate() when you create the player, you should set the listener there:
player = new MediaPlayer();
player.setOnPreparedListener(this)
And remove the other one, otherwise it'll override the first.
When you implement an interface, it's just setting a contract on the class: "this class has these particular methods, feel free to call them". MediaPlayer needs to know which OnPreparedListener to use (MediaPlayer.setOnPreparedListener) otherwise it won't do anything.
I am creating application which contains service that suppose to listen to calls,
and pop up an alert dialog after call has ended, the issue is, that as long as the activity running or in the background, the service works and the dialog pop up, but when I close the activity, the dialog wont pop up, as like the listener will not listen anymore to calls.
need help please!
this is how I call the service from my activity:
public void onClick(View v) {
switch (v.getId()) {
case R.id.start:
startService(new Intent(getBaseContext(), PhoneService.class));
break;
case R.id.stop:
stopService(new Intent(getBaseContext(), PhoneService.class));
break;
}
}
the service class:
public class PhoneService extends Service {
private static String TAG = "SERVICE";
int currentState;
Context context;
String incomingNumber;
#Override
public IBinder onBind(Intent arg0) {
// TODO Auto-generated method stub
return null;
}
// starts the service
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.i(TAG, "FirstService started");
context = this;
TelephonyManager telephony = (TelephonyManager) this.getSystemService(Context.TELEPHONY_SERVICE); // TelephonyManager
// object
CallListener listener = new CallListener();
telephony.listen(listener, PhoneStateListener.LISTEN_CALL_STATE);
// keeps the service going until explicitly stops
return START_STICKY;
}
#Override
public void onDestroy() {
// TODO Auto-generated method stub
super.onDestroy();
Log.i(TAG, "FirstService destroyed");
}
the listener class:
public class CallListener extends PhoneStateListener {
#Override
public void onCallStateChanged(int state, String incomingNumber) {
if (TelephonyManager.CALL_STATE_RINGING == state) {
// Incoming call handling
Log.i(TAG, " ring ring ring" + incomingNumber);
currentState = state;
}
if (TelephonyManager.CALL_STATE_OFFHOOK == state) {
// Outgoing call handling and answer
Log.i(TAG, " ofhook" + incomingNumber);
currentState = state;
}
if (TelephonyManager.CALL_STATE_IDLE == state) {
// Device back to normal state (not in a call)
Log.i(TAG, " idle" + incomingNumber);
if (currentState == TelephonyManager.CALL_STATE_OFFHOOK) {
Toast.makeText(context,"phone number dialed is "+ PhoneService.this.incomingNumber,Toast.LENGTH_SHORT).show();
AlertDialog.Builder builder = new AlertDialog.Builder(context);
builder.setMessage("Who is this person?").setCancelable(false).setPositiveButton("1",new DialogInterface.OnClickListener() {
public void onClick(
DialogInterface dialog, int id) {
}
})
.setNegativeButton("0",
new DialogInterface.OnClickListener() {
public void onClick(
DialogInterface dialog, int id) {
}
});
AlertDialog alert = builder.create();
alert.getWindow().setType(
WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
alert.show();
}
currentState = state;
}
}
}
Change your service to derive from IntentService and remove the overrides for onBind and onStartCommand (let the system handle those).
Put your code in the onHandleIntent override.
The different service types are handled differently - a bound service only operates while the activity is running, but an intent service can be started at any time. You can read more about service types here.
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.
I currently have a running service that receives messages from sockets every time another user sends someone a message. Now in the activity I can easily call a dialog to display a notice that a message has been received, however I want to do that from the running service. How can I get about with this?
Here is my running service.
public class MyService extends Service implements ChatCallbackAdapter {
public StartSocket connect;
public static Context mContent;
private ConnectSocket connectsocket;
final Context context = this;
#Override
public IBinder onBind(Intent arg0) {
// TODO Auto-generated method stub
return null;
}
#Override
public void onStart(Intent intent, int startId) {
System.out.println("Service is running");
connectsocket= new ConnectSocket(this);
connectsocket.start();
connect=new StartSocket();
}
public void startNotification(){
Intent intent = new Intent(this, ReceiveNotification.class);
PendingIntent pIntent = PendingIntent.getActivity(this, 0, intent, 0);
// Build notification
// Actions are just fake
Notification noti = new Notification.Builder(this)
.setContentTitle("Received a message")
.setContentText("Subject").setSmallIcon(R.drawable.ic_launcher)
.setContentIntent(pIntent)
.addAction(R.drawable.ic_launcher, "Rply", pIntent)
.build();
NotificationManager notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
// Hide the notification after its selected
noti.flags |= Notification.FLAG_AUTO_CANCEL;
notificationManager.notify(0, noti);
}
#Override
public void callback(JSONArray data) throws JSONException {
// TODO Auto-generated method stub
}
#Override
public void on(String event, JSONObject data) {
// TODO Auto-generated method stub
}
#Override
public void onMessage(String message) {
// TODO Auto-generated method stub
}
#Override
public void onMessage(JSONObject json) {
// TODO Auto-generated method stub
}
#Override
public void onConnect() {
// TODO Auto-generated method stub
}
#Override
public void onDisconnect() {
// TODO Auto-generated method stub
}
#Override
public void onConnectFailure() {
// TODO Auto-generated method stub
}
#Override
public void onMessageReceived(Message m) {
// TODO Auto-generated method stub
System.out.println("Received a message in service");
if(m.status.equals("ready")){
connectsocket.login(SaveSharedPreference.getUserName(getApplicationContext()), SaveSharedPreference.getUserId(getApplicationContext()));
connectsocket.subscribe();
}
if(m.status.equals("message")){
//getMsg(m.msg, m.name);
startNotification();
System.out.println("Received a message "+m.msg+" and a name "+m.name);
final String name=m.name;
final String pid=m.pid;
final String msg=m.msg;
//Intent intenter=new Intent(TabExercise.this, CreateNotification.class);
//startActivity(intenter);
//runOnUiThread(new Runnable(){
//public void run(){
//Handler handler = new Handler(Looper.getMainLooper());
AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(
context);
alertDialogBuilder.setTitle(name+" just sent you a message");
alertDialogBuilder.setMessage("Click yes to go to the message");
alertDialogBuilder
.setCancelable(false)
.setPositiveButton("Yes",new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog,int id) {
Intent inte=new Intent(MyService.this, Chat.class);
Bundle extras=new Bundle();
extras.putString("name", name);
extras.putString("pid", pid);
extras.putString("msg", msg);
inte.putExtras(extras);
startActivity(inte);
dialog.cancel();
}
})
.setNegativeButton("No",new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog,int id) {
// if this button is clicked, just close
// the dialog box and do nothing
dialog.cancel();
}
});
// create alert dialog
AlertDialog alertDialog = alertDialogBuilder.create();
// show it
alertDialog.show();
//}
//});
}
}
}
You have 2 options:
Use Messenger Pattern as explained in documentation here.
Use LocalBroadcastManager to send out a broadcast from service, and make the target activity implement BroadcastReceiver to listen to that broadcast.
An advantage the Messenger have is that service can select to notify one particular messenger of all its clients.