After restarting, Android plays default notification instead of custom(saved in sharedPreferences) - java

The three methods: ringtone(); onActivityResult(); saveRingtone(); do work.
During the first load of the app the fourth method loadRingtone(); works too, it can play repeatingly any sound the user chooses.
But as the app restarts:
It does save and bring back the string of the User's chosen notification sound. But just as its supposed to play the sound, converted from that string, it plays the default instead.
I used some toasts to check the values.
Toast.makeText(this,uri.toString(),Toast.LENGTH_SHORT).show();
Toast.makeText(this,ringPath,Toast.LENGTH_SHORT).show();
public void ringtone(View view){
final Uri currentTone = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
Intent intent = new Intent(RingtoneManager.ACTION_RINGTONE_PICKER);
intent.putExtra(RingtoneManager.EXTRA_RINGTONE_EXISTING_URI, currentTone);
intent.putExtra(RingtoneManager.EXTRA_RINGTONE_TYPE, RingtoneManager.TYPE_NOTIFICATION);
intent.putExtra(RingtoneManager.EXTRA_RINGTONE_TITLE, "Select Tone");
intent.putExtra(RingtoneManager.EXTRA_RINGTONE_EXISTING_URI, (Uri) null);
intent.putExtra(RingtoneManager.EXTRA_RINGTONE_SHOW_SILENT, false);
this.startActivityForResult(intent, 5);
}
#Override
protected void onActivityResult(final int requestCode, final int resultCode, final Intent intent) {
if (resultCode == Activity.RESULT_OK && requestCode == 5){
uri = intent.getParcelableExtra(RingtoneManager.EXTRA_RINGTONE_PICKED_URI);
if (uri == null) {
uri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
}
sound = RingtoneManager.getRingtone(getApplicationContext(), uri);
saveRingtone();
}
}
public void saveRingtone(){
SharedPreferences sharedPreferences = getSharedPreferences(SHARED_PREFS, MODE_PRIVATE);
SharedPreferences.Editor editor = sharedPreferences.edit();
editor.putString(Ring, uri.toString());
editor.apply();
}
public void loadRingtone(){
SharedPreferences sharedPreferences = getSharedPreferences(SHARED_PREFS, MODE_PRIVATE);
ringPath = sharedPreferences.getString(Ring, "");
if(ringPath == ""){
uri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
}else {
uri.parse(ringPath);
}
sound = RingtoneManager.getRingtone(getApplicationContext(), uri);
sound.play();
}
Its expected to play the notification that the "sound" variable is set up with in the loadRingtone(); method (not default sound).

Related

Android how to set and retrieve data from Preference object

I am working on a preference fragment, one preference is to select an external image file as the app background.
I try to save the file path string to the correspond preference, so that I can load that path data from SharedPreferences when the app is launched.
My problem is when using Preference class instead of EditTextPreference, there is no setText() method to save the path value, and I cannot figure out how to store the data onto a Preference object and then retrieve through SharedPreferences.getString("key", "") in my activity.
If I use a EditTextPreference instead, indeed it works but I have to disable or customize the dialog component of EditTextPreference, since I need to start a new activity to pick a image when tapping this preference.
I notice in the official documentation they use Preference when using intent together. Is there any way to save data to a Preference object and then retrieve that data in an activity?
// In preference fragment
private Preference bgPref;
#Override
public void onActivityResult(
int requestCode, int resultCode, #Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (resultCode == RESULT_OK && data != null) {
Uri imageUri = data.getData();
final String path = getFilePath(requireContext(), imageUri);
if (path != null) {
bgPref.setText(path); // how to set a string value for a Preference?
Drawable d = Drawable.createFromPath(path);
if (containerView != null) {
containerView.setBackground(d);
}
}
} else {
Toast.makeText(requireContext(), "You haven't picked Image", Toast.LENGTH_LONG).show();
}
}
// In Main activity
SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(this);
String bgPath = sharedPrefs.getString("bgPath", "");
Drawable d = Drawable.createFromPath(bgPath);
if (!bgPath.isEmpty()) findViewById(R.id.nav_host_fragment).setBackground(d);
//...
You can edit this preference directly. In onActivityResult():
#Override
public void onActivityResult(
int requestCode, int resultCode, #Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (resultCode == RESULT_OK && data != null) {
Uri imageUri = data.getData();
final String path = getFilePath(requireContext(), imageUri);
if (path != null) {
// Save preference here
SharedPreferences.Editor editor = sharedPrefs.edit();
editor.putString("bgPath", path);
editor.apply();
// Now recreate activity to refresh the UI
requireActivity().recreate();
// In onCreateView, you can use this preference to set background
}
} else {
Toast.makeText(requireContext(), "You haven't picked Image", Toast.LENGTH_LONG).show();
}
}
}

Send data from BroadcastReceiver to Activity in background(without starting)

I have this receiver class, it' registered in my MainActivity, it's supposed to count unlocks.
My goal
I want to make it work even when the app itself is not running(the receiver is never unregistered). It should get the amount of unlocks to the main activity without starting/restarting the activity.
My problem
I have no idea how to do that. As you can see I have tried to do it with SharedPreferences, but it didn't work, the receiver works fine and gets broadcasts, I just don't want it to start everytime.
public class UnlockReceiver extends BroadcastReceiver {
private int count = 0;
private SharedPreferences preferences;
private SharedPreferences.Editor editor;
private static final String TAG = "UnlockReceiver";
#Override
public void onReceive(Context context, Intent intent) {
preferences = context.getSharedPreferences("label", 0);
count = preferences.getInt("tag", 0);
KeyguardManager keyguardManager = (KeyguardManager)context.getSystemService(Context.KEYGUARD_SERVICE);
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.M) {
if (!keyguardManager.inKeyguardRestrictedInputMode()) {
count++;
editor = preferences.edit();
editor.putInt("tag", count).commit();
Log.d(TAG, "unlock registered");
Intent i = new Intent(context, MainActivity.class);
i.putExtra("tag", count);
context.sendBroadcast(i);
}
} else {
if (!keyguardManager.isDeviceLocked()) {
count++;
editor = preferences.edit();
editor.putInt("tag", count).commit();
Log.d(TAG, "unlock registered");
Intent i = new Intent(context, MainActivity.class);
i.putExtra("tag", count);
context.sendBroadcast(i);
}
}
}
}

Storing a high score in Android app

I have an app which displays the score on the main screen but this sets to zero every time a new game is started. What I want it to do is store that score and only change if the next score is higher, hence it being the highest score.
At the moment a hitCount method is deployed which a finish() method utilises to show the score from the game activity to the main activity.
The finish() method is below:
public void finish(){
Intent returnIntent = new Intent();
returnIntent.putExtra("GAME_SCORE", gameView.getHitCount());
setResult(RESULT_OK, returnIntent);
super.finish();
}
In the MainMenu class, the following onActivityResult() method is used to get the score to display on the main screen:
protected void onActivityResult(int requestCode, int resultCode, Intent retIntent) {
// Check which request we're responding to
if (requestCode == SCORE_REQUEST_CODE) {
// Make sure the request was successful
if (resultCode == RESULT_OK) {
if (retIntent.hasExtra("GAME_SCORE")) {
int scoreFromGame = retIntent.getExtras().getInt("GAME_SCORE");
tvScore.setText(Integer.toString(scoreFromGame));
//highScore.setText(Integer.toString(scoreFromGame));
}
}
}
}
Now, I know I must use something like shared preference to have any chance of storing the score and replacing it with a higher number when achieved but I can't figure out how and where.
As always, any help greatly appreciated.
Thanks
Put the following into your onCreate method to read the high score.
SharedPreferences sharedPref = getActivity().getPreferences(Context.MODE_PRIVATE);
// Read the high score from Shared Preference
int mHighScore = sharedPref.getInt(getString(R.string.high_score), 0);
Update your high score using Shared Preference:
protected void onActivityResult(int requestCode, int resultCode, Intent retIntent) {
// Check which request we're responding to
if (requestCode == SCORE_REQUEST_CODE) {
// Make sure the request was successful
if (resultCode == RESULT_OK) {
if (retIntent.hasExtra("GAME_SCORE")) {
int scoreFromGame = retIntent.getExtras().getInt("GAME_SCORE");
tvScore.setText(Integer.toString(scoreFromGame));
//highScore.setText(Integer.toString(scoreFromGame));
// Write the new high score to Shared Preference
SharedPreferences.Editor editor = sharedPref.edit();
if (scoreFromGame > mHighScore) {
editor.putInt(getString(R.string.high_score), scoreFromGame);
editor.commit();
}
}
}
}
}
You should definitively read about SharedPreferences and look at the link given in the comments. If you want a quick solution for now:
MainActivity.java
SharedPreferences prefs;
#Override
protected void onCreate(Bundle savedInstanceState) {
// Set highscore text on start
prefs = PreferenceManager.getDefaultSharedPreferences(this);
int highscore = prefs.getInt(PreferenceHelper.KEY_HIGHSCORE, 0);
tvHighScore.setText(Integer.toString(highscore));
}
protected void onActivityResult(int requestCode, int resultCode, Intent retIntent) {
// Check which request we're responding to
if (requestCode == SCORE_REQUEST_CODE) {
// Make sure the request was successful
if (resultCode == RESULT_OK) {
if (retIntent.hasExtra("GAME_SCORE")) {
int scoreFromGame = retIntent.getExtras().getInt("GAME_SCORE");
tvScore.setText(Integer.toString(scoreFromGame));
int highscore = prefs.getInt(PreferenceHelper.KEY_HIGHSCORE, 0); // Get highscore stored in prefs
if (scoreFromGame > highscore) {
// Update text and save new highscore
tvHighScore.setText(Integer.toString(scoreFromGame));
prefs.edit().putInt(PreferenceHelper.KEY_HIGHSCORE, scoreFromGame).apply();
}
}
}
}
}
PreferenceHelper.java
public final class PreferenceHelper {
public static final String KEY_HIGHSCORE = "highscore";
}
You don't have to use the PreferenceHelper class, but it's a good practice.

Avoiding FAILED BINDER TRANSACTION error using intent

In my costum camera app I need to transfer a bitmap and a Uri from one activity to another. For some reason I'm getting the FAILED BINDER TRANSACTION error on most phones(I get the error on newer phones but don't on Nexus4 and Galaxy3). I get the same error even when I only try to transfer the Bitmap through an intent(I also tried transfering only the Uri and got the error). From what I've read online the error comes from a memory problem but I don't know how to fix it. I would appreciate any kind of help.
My first Activity:
...
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if (resultCode == RESULT_OK) {
if (requestCode == SELECT_PICTURE) {
tv.setVisibility(View.INVISIBLE);
btn.setVisibility(View.INVISIBLE);
selectedImageUri = data.getData();
selectedImagePath = getPath(selectedImageUri);
System.out.println("Image Path : " + selectedImagePath);
img.setImageURI(selectedImageUri);
ok.setVisibility(View.VISIBLE);
}
}
}
public String getPath(Uri uri) {
String[] projection = { MediaStore.Images.Media.DATA };
Cursor cursor = managedQuery(uri, projection, null, null, null);
int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
cursor.moveToFirst();
return cursor.getString(column_index);
}
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
if(v.getId()==btn.getId())
{
Intent intent = new Intent();
intent.setType("image/*");
intent.setAction(Intent.ACTION_GET_CONTENT);
startActivityForResult(Intent.createChooser(intent, "Select Picture"), SELECT_PICTURE);
}
if(v.getId()==ok.getId())
{
String stringUri;
stringUri = selectedImageUri.toString();
Intent intent = new Intent(Intent.ACTION_VIEW);
intent .setClass(MainActivity.this, SecondMain.class);
intent .putExtra("KEY", stringUri);
startActivity(intent );
}
}
}
Second Activity:
public static Camera isCameraAvailiable(){
Camera object = null;
try {
object = Camera.open();// attempt to get a Camera instance
}
catch (Exception e){
// Camera is not available (in use or does not exist)
}
return object; // returns null if camera is unavailable
}
private Camera.PictureCallback capturedIt = new Camera.PictureCallback() {
#Override
public void onPictureTaken(byte[] data, Camera camera) {
bitmap = BitmapFactory.decodeByteArray(data, 0, data.length);
if(bitmap==null){
Toast.makeText(getApplicationContext(), "not taken", Toast.LENGTH_SHORT).show();
}
else
{
Toast.makeText(getApplicationContext(), "taken", Toast.LENGTH_SHORT).show();
}
cameraObject.release();
}
};
...
String stringUri = null;
Bundle extras = getIntent().getExtras();
if (extras != null && extras.containsKey("KEY")) {
stringUri= extras.getString("KEY");
}
selectedImageUri = Uri.parse(extras.getString("KEY"));
float alpha=(float)1/2;
img.setAlpha(alpha);
img.setImageURI(selectedImageUri);
cameraObject = isCameraAvailiable();
showCamera = new ShowCamera(this, cameraObject);
frame.addView(showCamera);
}
public void snapIt(View view){
redo.setVisibility(View.VISIBLE);
ok.setVisibility(View.VISIBLE);
snap.setVisibility(View.INVISIBLE);
cameraObject.takePicture(null, null, capturedIt);
}
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
if(v.getId()==ok.getId())
{
Intent intent = new Intent(SecondMain.this, Blend.class);
ByteArrayOutputStream stream=new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.PNG, 100, stream);
byte[]byteArray=stream.toByteArray();
intent.putExtra("image", byteArray);
String stringUri;
stringUri = selectedImageUri.toString();
intent .putExtra("KEY", stringUri);
startActivity(intent);
It is not a memory problem, it's a problem with transferring your image with your intent. You see, Bundle has a limit of how much data it can transfer from one end to the other, currently it's only 1MB. You will problems on all modern phones with a decent camera, as the image exceeds 1MB limit, some old phones with low end camera will work. You need to rethink on how you are going to be transfering the image.
You can
Save it to a file first, send the only the path to it (that's how selecting an image from the gallery works)
Save it to SQL and retrive it on the other end
Make a hodler class with a static variable of image (the most simple)
Make a custom class of Application and put it there for the time being.
Downscale and compress the image before it's transferred

Building a Camera App - Receive

I am new to Android programming and I'm writing an application in Java that opens the camera take a photo and save it. I made it via Intents but I can't see onActivityResult running.
I have tested it into my phone (Samsung Galaxy S) and when I take the photo I receive a preview of that photo having two buttons one Save and the other Cancel. I haven't added something to my code to do this so I think it's something that camera does. I want after capturing the image to run onActivityResult (after I press the Save button on the preview).
But how I'm going to return a result to start onActivityResult after pressing the Button Save on the preview?
I FORGOT to tell that after i press save my entire app is terminated.
Here is my Code
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
TakePicButton = (Button) findViewById(R.id.TakePicture);
TakePicButton.setOnClickListener((android.view.View.OnClickListener) this);
}
#Override
public void onDestroy(){
super.onDestroy();
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == CAPTURE_IMAGE_ACTIVITY_REQUEST_CODE) {
if (resultCode == RESULT_OK) {
// Image captured and saved to fileUri specified in the Intent
Toast.makeText(this, "Image saved to:\n" + data.getData(), Toast.LENGTH_LONG).show();
} else if (resultCode == RESULT_CANCELED) {
Toast.makeText(this, "Picture was not taken", Toast.LENGTH_SHORT);
} else {
Toast.makeText(this, "Picture was not taken", Toast.LENGTH_SHORT);
}
}
public void onClick(View v) {
// TODO Auto-generated method stub
if(v.getId() == R.id.TakePicture){
// create Intent to take a picture and return control to the calling application
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
fileUri = getOutputMediaFileUri(MEDIA_TYPE_IMAGE); // create a file to save the image
intent.putExtra(MediaStore.EXTRA_OUTPUT, fileUri); // set the image file name
// start the image capture Intent
startActivityForResult(intent, CAPTURE_IMAGE_ACTIVITY_REQUEST_CODE);
}
}
try the below code, you will have to modify it a bit, it will help you get From Library and From Camera both, the SELECT_PICTURE is used for getting image from library
public void onActivityResult(int requestCode, int resultCode, Intent data) {
switch (requestCode) {
case SELECT_PICTURE:
Uri selectedImageUri = data.getData();
filemanagerstring = selectedImageUri.getPath();
selectedImagePath = getPath(selectedImageUri);
if (selectedImagePath != null)
myFile = new File(selectedImagePath);
else if (filemanagerstring != null)
myFile = new File(filemanagerstring);
if (myFile != null) {
Bitmap bmp_fromGallery = decodeImageFile(selectedImagePath);
break;
case CAMERA_REQUEST:
Bitmap bmp_Camera = (Bitmap) data.getExtras().get("data");
break;
default:
break;
}
}

Categories

Resources