I would like to check programmatically whether an sd card is installed, and if yes, give the user the choice to switch between external and internal storage.
I have my other static settings organized inside a preferences.xml.
It seems that I have to rewrite all the settings of the xml file in code if I start to work with preferences more dynamically.
Or is there an option to enhance the preferences from the xml with preferences from code which get used just once needed?
Thanks
Add this to manifest for install app on sd card if is possible:
android:installLocation="preferExternal">
To verify is sd card writable and readable use this method:
private boolean isExternalStorageWritable() {
return Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED);}
To get folder of appfiles on sdCard (externalStorageVolumes[0] is primary folder):
File[] externalStorageVolumes =
ContextCompat.getExternalFilesDirs(getApplicationContext(), null);
Oficial documentation
I found out myself, it looks a bit clumsy, but it works.
Once again: My problem is that I have certain setting options pre configured in an xml file as described here:
Preferences with XML
Here is my preferences.xml:
<PreferenceScreen xmlns:app="http://schemas.android.com/apk/res-auto">
<PreferenceCategory app:title="#string/download_header">
<SwitchPreferenceCompat
app:key="dl_background"
app:title="#string/background_behaviour"
app:defaultValue="false"/>
<ListPreference
app:title="#string/dl_qual"
app:defaultValue="#string/low_qual"
app:key="dl_qual"
app:entries="#array/dl_qual_arry"
app:entryValues="#array/dl_qual_arry"/>
</PreferenceCategory>
<PreferenceCategory app:title="#string/tc_header">
<SwitchPreferenceCompat
app:key="tc_installed"
app:title="#string/tc_behaviour"
app:defaultValue="false"/>
<ListPreference
app:title="#string/dl_dir_root"
app:key="dl_dir_root"/>
</PreferenceCategory>
</PreferenceScreen>
Here you can define arrays which map to ListPrefrence objects.
Each option list is then populated from a resource xml file holding the actual list entries.
I used this approach for the first ListPreference "dl_qual" above.
This is the resource.xml file:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string-array name="dl_qual_arry">
<item>Higher quality (128kbps)</item>
<item>Lower quality (64kbps)</item>
</string-array>
</resources>
But then I had the idea to insert a ListPreference where the values of the options list are only known at runtime.
This is my second ListPreference above "dl_dir_root".
I was too lazy to rewrite (and read how to do it in advance) the complete settings activity from code.
So I ended up with this SettingsFragment inside my SettingsActivity:
public static class SettingsFragment extends PreferenceFragmentCompat {
#Override
public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
//First, lets check whether we have initialized preferences already
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getContext());
String selectedDir = prefs.getString("dl_dir_root", "INIT");
setPreferencesFromResource(R.xml.root_preferences, rootKey);
PreferenceScreen root = getPreferenceScreen();
ListPreference dlDirRoot = root.findPreference("dl_dir_root");
CharSequence[] arryValues = BBCWorldServiceDownloaderUtils.getStoragePaths(getContext());
CharSequence[] arryEntrys = BBCWorldServiceDownloaderUtils.getStoragePaths(getContext());
dlDirRoot.setEntries(arryEntrys);
dlDirRoot.setEntryValues(arryValues);
if(selectedDir.equals("INIT")) {
//Initialize value/index
dlDirRoot.setDefaultValue(arryValues[0]);
dlDirRoot.setValueIndex(0);
}
else{
//Position at already selected value/index
dlDirRoot.setDefaultValue(selectedDir);
dlDirRoot.setValue(selectedDir);
dlDirRoot.setValueIndex(dlDirRoot.findIndexOfValue(selectedDir));
}
}
}
The pre defined xml is applied first, then the ListPreference object for "dl_dir_root" is acessed and the options are added:
ListPreference dlDirRoot = root.findPreference("dl_dir_root");
CharSequence[] arryValues = BBCWorldServiceDownloaderUtils.getStoragePaths(getContext());
CharSequence[] arryEntrys = BBCWorldServiceDownloaderUtils.getStoragePaths(getContext());
dlDirRoot.setEntries(arryEntrys);
dlDirRoot.setEntryValues(arryValues);
The rest is checking/keeping state between the calls to the activity.
If anyone knows of a more elegant way, I would be curious.
Best
Matthias
Related
I am making a simple Android game that displaying a sequence of visual stimuli. I have two activities (Main & Settings). In the setting you will be able to edit the number of stimuli. When I edit the number it does not update at the main activity.
This is into Main activity onCreate
settings = new SettingsActivity();
setNrOfStimuli = settings.getSetNrOfStimuli();
stimuli = new int[setNrOfStimuli];
This is on Main activity
public void onSettingBtnClicked(View view) {
startActivity(new Intent(getApplicationContext(),SettingsActivity.class));
}
This is on Settings activity
public void onBackBtnClicked(View view) {
setNrOfStimuli = Integer.parseInt(inputNrOfStimuliView.getText().toString());
finish();
}
I can transfer the value of number by Intent or getter & setter but the problem is with initialization when it comes back to Main activity from Settings.
I think you should use SharedPreferences to store user's settings. You can go through this tutorial to learn about it.
https://www.javatpoint.com/android-preferences-example
You have to change this in the tutorial's code:
In prefs.xml:
<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
<!-- you do not worry about how this information will be stored, it will be handled
by the android. You have to use those data by getting that data by their key -->
<EditTextPreference
android:key="stimuli_numbers"
android:summary="Please enter Number of stimuli"
android:inputType="numberDecimal"
android:digits="0123456789"
android:title="Number of stimuli" />
</PreferenceScreen>
and in your Main Activity
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(MainActivity.this);
//get the number of stimuli
//stimuli_numbers is the key and 0 is the default value (you can change this according to yours.
setNrOfStimuli = Integer.valueOf(prefs.getString("stimuli_numbers","0");
I'm trying to backup/restore shared preferences of my app, I followed this step using Android Backup Service:
In Manifest.xml in <application> tag
<meta-data android:name="com.google.android.backup.api_key" android:value="My Key" />
added this class:
public class MyBackupAgent extends BackupAgentHelper {
// The name of the SharedPreferences file
static final String PREFS = "my_preferences";
#Override
public void onCreate() {
SharedPreferencesBackupHelper helper = new SharedPreferencesBackupHelper(this, PREFS);
addHelper(Utilities.SETTINGS_KEY, helper);
}
}
when set value to shared preference I do this:
BackupManager backupManager = new BackupManager(context);
backupManager.dataChanged();
But if I uninstall/reinstall app, changes doesn't apply...
My guess is you forgot to add
android:allowBackup="true"
inside your <application> tag in the AndroidManifest.xml file
You have to allocate a helper and add it to the backup agent like this:
#Override
public void onCreate() {
FileBackupHelper helper = new FileBackupHelper(this,
TOP_SCORES, PLAYER_STATS);
addHelper(FILES_BACKUP_KEY, helper);
}
and also consider overriding onBackup() and onRestore() methods.
See explanation here:
https://developer.android.com/guide/topics/data/keyvaluebackup.html#BackupAgentHelper
when you call dataChanged() you just notify system that something is changed, it does not start backup in this moment, give it some time and wi fi connection. Check in your device's settings under 'Backup and reset' if 'automatic restore' is set.
Make sure that you writing to the same preferences (with the same key) which you are saving context.getSharedPreferences("my_preferences", Context.MODE_PRIVATE);
I assume you have setting something like this (depends on android version and even on the device)
"Cloud and Accounts"->"Backup and Restore"->"Automatic restoration"
turned on. If not, turning it on may solve your problem.
I am following the code lab tutorial.
My Gradle file looks like this
dependencies {
compile 'com.android.support:appcompat-v7:25.0.0'
compile 'com.android.support:mediarouter-v7:25.0.0'}
This is my CastOptionsProvider class
public class CastOptionsProvider implements OptionsProvider {
#Override
public CastOptions getCastOptions(Context context) {
return new CastOptions.Builder()
.setReceiverApplicationId(context.getString(R.string.chromecast_app_id))
.build();
}
#Override
public List<SessionProvider> getAdditionalSessionProviders(Context context) {
return null;
}}
This is the menu xml file
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools">
<item
android:id="#+id/media_route_menu_item"
android:title="#string/media_route_menu_title"
app:actionProviderClass="android.support.v7.app.MediaRouteActionProvider"
app:showAsAction="always" /></menu>
And this is my OnCreateOptionsMenu method in MainActivity
#Override
public boolean onCreateOptionsMenu(Menu menu) {
super.onCreateOptionsMenu(menu);
getMenuInflater().inflate(R.menu.navigation_drawer, menu);
mediaRouteMenuItem = CastButtonFactory.setUpMediaRouteButton(getApplicationContext(), menu, R.id.media_route_menu_item);
return true;
}
And this in the manifest file
<meta-data
android:name="com.google.android.gms.cast.framework.OPTIONS_PROVIDER_CLASS_NAME"
android:value="com.mypackage.CastOptionsProvider" />
I have followed the codelab tutorial to its exact form, copy and pasted everything while changing those variable which needs to be changed.
My application and the chromecast device are connected to the same network. The Chromecast button appears in the Youtube app but not on my app. What am I missing ?
Thanks
It might be an invalid app_id.
You might try replacing your chromecast_app_id string resource with the app_id string resource value from the sample project.
(Right now, it's 4F8B3483. See: https://github.com/googlecast/CastVideos-android/blob/master/res/values/strings.xml).
Believe it or not, switching to that value made the cast icon visible in my app.
If everything is done properly, you just need to restart cast device (it does not work with your app_id without restarting after registration).
Check in Google Cast SDK Developer Console if your Application ID is correct and status is Published.
When publish your Application ID, restart your Chromecast device.
For testing purposes, you can use CC1AD845 or 4F8B3483 as Application ID. These are from Google sample apps.
Adding another answer as the accepted answer did nothing for me. The issue happened to me only when building a proguarded version of my app.
I had to add a couple lines to my proguard file (essentially all of the classes referenced by xml as mentioned here: https://stackoverflow.com/a/24578823/1048847)
-keep class com.your.package.CastOptionsProvider { *; }
// I have a custom MediaRouteActionProvider but this may need to be
// android.support.v7.app.MediaRouteActionProvider in the case of OP
-keep class com.your.package.MediaRouteActionProvider { *; }
you are missing attribute icon here
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools">
<item
android:id="#+id/media_route_menu_item"
android:title="#string/media_route_menu_title"
android:icon="#drawable/chromebutton" app:actionProviderClass="android.support.v7.app.MediaRouteActionProvider"
app:showAsAction="always" /></menu>
I'm trying to set a defaultValue to a ListPreference item.
Here is an sample of my preference.xml file:
<ListPreference android:key="notification_delay"
android:title="#string/settings_push_delay"
android:entries="#array/settings_push_delay_human_value"
android:entryValues="#array/settings_push_delay_phone_value"
android:defaultValue="????">
</ListPreference>
The two arrays:
<string-array name="settings_push_delay_human_value">
<item>every 5 minutes</item>
<item>every 10 minutes</item>
<item>every 15 minutes</item>
</string-array>
<string-array
name="settings_push_delay_phone_value">
<item>300</item>
<item>600</item>
<item>900</item>
</string-array>
When i go into the preference activity, no item of the ListPreference is selected. I've tried to set an int value like 1 in the "android:defaultValue" fied to select "10 minutes" but it does not work.
<ListPreference android:key="notification_delay"
android:title="#string/settings_push_delay"
android:entries="#array/settings_push_delay_human_value"
android:entryValues="#array/settings_push_delay_phone_value"
android:defaultValue="1">
</ListPreference>
Any Idea?
You need to specify the value. So to get the first entry selected by default specify defaultValue="300" in your example.
Happened to be in same situation. Specifying a consistent default value. But graphically was not selected. I cleared the application data. And then it worked as expected.
So a clear may be useful at dev time when adding new XxxPreference items.
In addition to Sven's answer, you have to call the setDefaultValues() method in the starting activity. This will set once all default values.
public class MainActivity extends Activity {
protected void onCreate(final Bundle savedInstanceState) {
// Set all default values once for this application
// This must be done in the 'Main' first activity
PreferenceManager.setDefaultValues(this, R.xml.preferences, false);
...
}
}
If it is a valid value from the list, then re-install the app. It will work.
Could someone maybe tell me what i'm doing wrong? I'm betting im missing one small thing. I've looked on the developer site and i've read some tutorials and i'm just not seeing what i did wrong.
I'm trying to use a ListPreference to decide which sound to play on a button click.
I have this at the top:
public String greensound;
Here's my OnClick code:
case R.id.green:
SharedPreferences prefs=PreferenceManager.getDefaultSharedPreferences(this);
greensound = prefs.getString("greensound", "gsone");
if (greensound == "gsone") {
mSoundManager.playSound(1);
} else if (greensound == "gstwo") {
mSoundManager.playSound(2);
} else if (greensound == "gsthree") {
mSoundManager.playSound(3);
}
break;
Here's my xml:
<ListPreference
android:title="Geen Button"
android:key="greensound"
android:summary="Select sound for the Green Button"
android:entries="#array/green_list"
android:entryValues="#array/green_list_values"
android:defaultValue="gsone">
</ListPreference>
here's my Settings.java:
package com.my.app;
import android.os.Bundle;
import android.preference.PreferenceActivity;
public class Settings extends PreferenceActivity {
#Override
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.settings);
}
}
and here's my array's if that will help at all:
//This is the one I want to display to the user
<string-array name="green_list">
<item>Sound One</item>
<item>Sound Two</item>
<item>Sound Three</item>
<item>Sound Four</item>
<item>Sound Five</item>
</string-array>
<string-array name="green_list_values">
<item>gsone</item>
<item>gstwo</item>
<item>gsthree</item>
<item>gsfour</item>
<item>gsfive</item>
</string-array>
edit: added a logcat that kinda looked possibly related.
08-27 01:52:07.738: WARN/Resources(6846): Converting to string: TypedValue{t=0x12/d=0x0 a=2 r=0x7f090000}
08-27 01:52:07.748: WARN/Resources(6846): Converting to string: TypedValue{t=0x12/d=0x0 a=2 r=0x7f090000}
08-27 01:52:07.758: WARN/Resources(6846): Converting to string: TypedValue{t=0x12/d=0x0 a=2 r=0x7f090000}
DDMS > File Explorer > Data > Data > packageName > SharedPreferences
This is what was in there:
com.my.app_preferences.xml:
<?xml version='1.0' encoding='utf-8' standalone='yes' ?>
<map>
<string name="redsound">rsone</string>
<string name="greensound">gsone</string>
</map>
_has_set_default_values.xml:
<?xml version='1.0' encoding='utf-8' standalone='yes' ?>
<map>
<boolean name="_has_set_default_values" value="true" />
</map>
This all really confuses me more because...It looks like greedsound does infact = gsone
so.... I don't understand whats wrong its not even playing the default sound. and yes i've tested
mSoundManager.playSound(1);
mSoundManager.playSound(2);
mSoundManager.playSound(3);
all without the other code and they work great. I'm not sure what's work
greensound.equals("gsone")
I had a similar problem. I changed my '==' comparisons to string.contentsEquals() and things started working. I eventually ended up putting the keys and values into HashMaps.
The only issue I can think of is that your preferences are not getting set before you are running your playSound code. To ensure the settings are loaded include the following code in your onCreate():
/* Loading default preferences the first time application is run */
PreferenceManager.setDefaultValues(getApplicationContext(),
R.xml.filename, false);
Also, check through the DDMS > File Explorer > Data > Data > packageName > SharedPreferences that your preferences are getting set.
When you are using Preference Activity and creating it from xml resource. It automatically creates a SharedPreference file: packageName_preferences (eg. com.my_company.my_app_preferences). Thus to access this you need to use the following code:
SharedPreferences prefs = getSharedPreferences("com.my.app_preferences", MODE_PRIVATE);
And finally remove the following line in the xml:
android:defaultValue="gsone"
Hope this helps.