I'm having some weird, inconsistent behaviour regarding the physical menu button in my application.
The following may or may not be helpful:
I have an app which changes its UI dependent on the device + screen size + orientation. On tablets in a landscape orientation, I use an activity with 2 fragments viewed simultaneously (contacts list + the chat of the selected contact). On phones, and on the tablet in portrait orientation, I instead use 2 separate activities; one for the contacts list and one for the chat.
I mention this because of the following weird behaviour that I am observing: the physical menu button on my devices is unresponsive in my app on both the phone, and on the tablets portrait orientation. When the tablet is in landscape orientation, the physical button does work as expected (which is show the overflow menu of my action bar). The menu button works correctly outside of my app.
I originally thought the issue was with my phone's version of android, but given that I'm also seeing the problem with the tablet in the portrait orientation, I'm not sure where the problem might lie. I did not hardcode any code for the physical menu button, so it shouldn't be a case of some functionality not being appropriately replicated for the single-pane view of the phone and portrait-oriented tablet.
Any ideas or answers would be greatly appreciated!
Thanks
EDIT: Added requested code.
The portrait orientation activity:
package com.h.r.android.tcip;
import android.content.ComponentName;
import android.content.ContentUris;
import android.content.Intent;
import android.content.ServiceConnection;
import android.content.pm.ActivityInfo;
import android.content.res.Configuration;
import android.database.ContentObserver;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.support.v4.app.Fragment;
import android.util.Log;
import com.actionbarsherlock.view.Menu;
import com.actionbarsherlock.view.MenuItem;
import com.h.r.android.tctip.ConversationFragment.Builder;
import com.h.r.android.tctip.data.TacMessage;
import com.h.r.android.tctip.db.AddressmessageSchema;
import com.h.r.android.tctip.settings.PreferencesHelper;
public class ConversationActivity extends LoggedInTCActivity {
#SuppressWarnings("unused")
private final String TAG = ConversationActivity.class.getSimpleName();
/**
* Projection for address database query results.
*/
protected static final String[] ADDRESS_PROJECTION = new String[] {
AddressmessageSchema.UID, AddressmessageSchema.HANDLE };
/**
* The TCService running in the background doing the send/receive work.
*/
protected TCService mService;
/**
* Handler used for the partner handle cursor.
*/
protected final Handler mHandler = new Handler();
/**
* Used to track partner handle changes.
*/
protected ContentObserver mHandleObserver = new ContentObserver(mHandler) {
/*
* (non-Javadoc)
*
* #see android.database.ContentObserver#onChange(boolean)
*/
#Override
public void onChange(boolean selfChange) {
super.onChange(selfChange);
getSupportActionBar().setTitle(getPartnerHandle());
}
};
/**
* The actual partner ID, from the intent.
*/
static long mPartnerId;
/**
* The connection binding us to the Service. We're using this to
* indicate to Android the dependency between this Activity and the running
* Service.
*/
protected final ServiceConnection mConnection = new ServiceConnection() {
/*
* (non-Javadoc)
*
* #see
* android.content.ServiceConnection#onServiceDisconnected(android.content
* .ComponentName)
*/
public void onServiceDisconnected(ComponentName name) {
mService = null;
}
/*
* (non-Javadoc)
*
* #see
* android.content.ServiceConnection#onServiceConnected(android.content
* .ComponentName, android.os.IBinder)
*/
public void onServiceConnected(ComponentName name, IBinder service) {
mService = ((TCService.TCServiceBinder) service)
.getService();
}
};
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setTheme(PreferencesHelper.getThemeId(this));
ConversationFragment frag = new ConversationFragment.Builder(
getIntent().getExtras()).build();
setContentView(R.layout.tc_conv);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
/*
if (savedInstanceState != null)
{
mPartnerId = savedInstanceState.getLong("mPartnerId", mPartnerId);
}
else{
*/
// The Fragment's partnerId
mPartnerId = frag.getPartnerId();
//}
getSupportActionBar()
.setTitle(
mPartnerId == 0 ? getString(R.string.tc_all_users_chat)
: getPartnerHandle());
getSupportFragmentManager().beginTransaction()
.add(R.id.conversation, frag).commit();
}
#Override
protected void onResume() {
super.onResume();
startService(new Intent(this, TCService.class));
//startService(new Intent(this, DiscoveryService.class));
// bind to the service to disable notifications while this is up
bindService(new Intent(this, TCService.class), mConnection, 0);
if (mPartnerId != 0) {
Uri handleUri = ContentUris.withAppendedId(TacMessage.ADDRESS_URI,
mPartnerId);
getContentResolver().registerContentObserver(handleUri, true,
mHandleObserver);
mHandleObserver.onChange(true);
}
}
/*
* (non-Javadoc)
*
* #see android.support.v4.app.FragmentActivity#onPause()
*/
#Override
protected void onPause() {
if (mService != null) {
unbindService(mConnection);
}
if (mPartnerId != 0) {
getContentResolver().unregisterContentObserver(mHandleObserver);
}
super.onPause();
}
/**
* Get the partner handle to show in the action bar.
*
* #return
*/
protected String getPartnerHandle() {
// Generic default in case something goes wrong.
String partnerHandle = getString(R.string.t_c_app_name);
Cursor c = null;
try {
String selection = AddressmessageSchema.UID + " = ?";
String[] selectionArguments = { "" + mPartnerId };
c = getContentResolver().query(TacMessage.ADDRESS_URI,
ADDRESS_PROJECTION, selection, selectionArguments, null);
if (c != null && c.moveToFirst()) {
partnerHandle = c.getString(c
.getColumnIndex(AddressmessageSchema.HANDLE));
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if (c != null) {
c.close();
}
}
return partnerHandle;
}
/*
* Can be called from screen orientation change or keyboard hidden. This is
* being used to prevent the Activity from being destroyed or rebuilt so
* that during zip and image conversion activities, we don't end up killing
* the app by rotating the screen and such.
*
* (non-Javadoc)
*
* #see
* android.support.v4.app.FragmentActivity#onConfigurationChanged(android
* .content.res.Configuration)
*/
#Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE)
{
//Builder.CONTACT_UID = getString((int) mPartnerId);
Log.d("gabe", "the config is changing in convo activity" + mPartnerId);
//finish();
}
// Pass in the orientation of sensor so that we keep receiving these
// calls.
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR);
}
public void onDestroy(Bundle savedInstanceState)
{
Log.d("gabe", "the conver activity is being destroyed" + mPartnerId);
}
public void onSaveInstance(Bundle savedInstanceState)
{
Log.d("gabe", "the con act is c saving instance");
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// TODO Auto-generated method stub
getSupportMenuInflater().inflate(R.menu.chat_only_menu, menu);
return super.onCreateOptionsMenu(menu);
}
/*
* Add the up (ancestral) navigation.
*
* (non-Javadoc)
*
* #see
* com.actionbarsherlock.app.SherlockFragmentActivity#onOptionsItemSelected
* (android.view.MenuItem)
*/
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
// Ancestral navigation (Home/Up button on Action Bar)
Intent parentActivityIntent = new Intent(this,
TCActivity.class);
// See the ancestral navigation docs about synthesizing a back
// stack, if we ever have need for more back steps than the
// TCActivity class.
// http://developer.android.com/training/implementing-navigation/ancestral.html
parentActivityIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP
| Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(parentActivityIntent);
finish();
return true;
}
return super.onOptionsItemSelected(item);
}
#Override
public boolean onContextItemSelected(android.view.MenuItem item) {
// TODO Auto-generated method stub
Fragment fragment = (Fragment) getSupportFragmentManager().findFragmentById(R.id.conversation);
if( null != fragment ) {
fragment.onContextItemSelected(item);
}
return super.onContextItemSelected(item);
}
}
The xml for the portrait activity, probably not what you wanted
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/conversation"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</LinearLayout>
chat only xml
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android" >
<group
android:id="#+id/group_alert_checked"
android:checkableBehavior="all" >
<item
android:id="#+id/menu_alert"
android:checked="false"
android:icon="?attr/buttonface_alert_unchecked"
android:showAsAction="always"
android:title="#string/menu_set_alert_message_mode"/>
</group>
<item
android:id="#+id/menu_attach_existing_picture"
android:icon="?attr/buttonface_existing_picture"
android:showAsAction="always"
android:title="#string/menu_attach_existing_picture">
</item>
<item
android:id="#+id/menu_attach_new_picture"
android:icon="?attr/buttonface_new_picture"
android:showAsAction="always"
android:title="#string/menu_attach_new_picture">
</item>
<item
android:id="#+id/menu_attach_file"
android:icon="?attr/buttonface_attach_file"
android:showAsAction="always"
android:title="#string/menu_attach_file">
</item>
<item
android:icon="?attr/buttonface_overflow"
android:showAsAction="always">
<menu>
<item
android:id="#+id/menu_add"
android:showAsAction="ifRoom"
android:title="#string/menu_new_contact">
</item>
<item
android:id="#+id/menu_clear_conversation"
android:showAsAction="ifRoom"
android:title="#string/menu_clear_conversation">
</item>
<item
android:id="#+id/menu_save_conversation"
android:showAsAction="ifRoom"
android:title="#string/menu_save_conversation">
</item>
<item
android:id="#+id/menu_logout"
android:showAsAction="ifRoom"
android:title="#string/logout"/>
</menu>
</item>
</menu>
I also have the code for the fragment and the fragments xml, which might also be useful to you, but the fragment code is very large. I recognize that the xml for the activity isn't very helpful as is without the rest though. Let me know what else would help and I'll figure out a better way of sharing.
Ok, I think you need to edit your onOptionsItemSelected override to handle the different menu items, here is an example that uses an if else instead of switch as using switches has issues in library projects.
#Override
public boolean onOptionsItemSelected(MenuItem item) {
int itemId = item.getItemId();
if (itemId == R.id.menu_alert) {
// do something here
return true;
} else if (itemId == R.id.menu_attach_existing_picture) {
// do something here
return true;
} else if (itemId == R.id.menu_attach_new_picture) {
// do something here
return true;
} else if (itemId == R.id.menu_attach_file) {
// do something here
return true;
} else if (itemId == R.id.menu_add) {
// do something here
return true;
} else if (itemId == R.id.menu_clear_conversation) {
// do something here
return true;
} else if (itemId == R.id.menu_save_conversation) {
// do something here
return true;
} else if (itemId == R.id.menu_logout) {
// do something here
return true;
} else if (itemId == android.R.id.home) {
// Ancestral navigation (Home/Up button on Action Bar)
Intent parentActivityIntent = new Intent(this,
TCActivity.class);
// See the ancestral navigation docs about synthesizing a back
// stack, if we ever have need for more back steps than the
// TCActivity class.
// http://developer.android.com/training/implementing-navigation/ancestral.html
parentActivityIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP
| Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(parentActivityIntent);
finish();
return true;
} else if (super.onOptionsItemSelected(item)) {
// parent activity handled this selection
return true;
}
return false;
}
Related
I have decided to restructure my question. I am trying to create a settings class for my Android app. I found I could automatically generate a basic layout of a settings activity in Android. The only problem I am facing is how to change the background color. I am aware it is made up of fragments and preference screens. however there is no XML file within the layout folder for me to edit the background color of this screen:
Screen 1
The rest of my app is set to retrieve a gradient style background which I have in my #drawable folder. Therefore it is not as simple as just calling a bold color. See below
Drawable folder
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<shape>
<gradient
android:angle="90"
android:startColor="#8e9eab"
android:endColor="#eef2f3"
android:type="linear"/>
</shape>
</item>
there is also XML preference screen files. but changing these to suit the background color has no effect.
xml files
below is all the code for my SettingActivity.java
public class SettingsActivity extends AppCompatPreferenceActivity {
/**
* A preference value change listener that updates the preference's summary
* to reflect its new value.
*/
private static Preference.OnPreferenceChangeListener sBindPreferenceSummaryToValueListener = new Preference.OnPreferenceChangeListener() {
#Override
public boolean onPreferenceChange(Preference preference, Object value) {
String stringValue = value.toString();
if (preference instanceof ListPreference) {
// For list preferences, look up the correct display value in
// the preference's 'entries' list.
ListPreference listPreference = (ListPreference) preference;
int index = listPreference.findIndexOfValue(stringValue);
// Set the summary to reflect the new value.
preference.setSummary(
index >= 0
? listPreference.getEntries()[index]
: null);
} else if (preference instanceof RingtonePreference) {
// For ringtone preferences, look up the correct display value
// using RingtoneManager.
if (TextUtils.isEmpty(stringValue)) {
// Empty values correspond to 'silent' (no ringtone).
preference.setSummary(R.string.pref_ringtone_silent);
} else {
Ringtone ringtone = RingtoneManager.getRingtone(
preference.getContext(), Uri.parse(stringValue));
if (ringtone == null) {
// Clear the summary if there was a lookup error.
preference.setSummary(null);
} else {
// Set the summary to reflect the new ringtone display
// name.
String name = ringtone.getTitle(preference.getContext());
preference.setSummary(name);
}
}
} else {
// For all other preferences, set the summary to the value's
// simple string representation.
preference.setSummary(stringValue);
}
return true;
}
};
/**
* Helper method to determine if the device has an extra-large screen. For
* example, 10" tablets are extra-large.
*/
private static boolean isXLargeTablet(Context context) {
return (context.getResources().getConfiguration().screenLayout
& Configuration.SCREENLAYOUT_SIZE_MASK) >= Configuration.SCREENLAYOUT_SIZE_XLARGE;
}
/**
* Binds a preference's summary to its value. More specifically, when the
* preference's value is changed, its summary (line of text below the
* preference title) is updated to reflect the value. The summary is also
* immediately updated upon calling this method. The exact display format is
* dependent on the type of preference.
*
* #see #sBindPreferenceSummaryToValueListener
*/
private static void bindPreferenceSummaryToValue(Preference preference) {
// Set the listener to watch for value changes.
preference.setOnPreferenceChangeListener(sBindPreferenceSummaryToValueListener);
// Trigger the listener immediately with the preference's
// current value.
sBindPreferenceSummaryToValueListener.onPreferenceChange(preference,
PreferenceManager
.getDefaultSharedPreferences(preference.getContext())
.getString(preference.getKey(), ""));
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setupActionBar();
}
/**
* Set up the {#link android.app.ActionBar}, if the API is available.
*/
private void setupActionBar() {
ActionBar actionBar = getSupportActionBar();
if (actionBar != null) {
// Show the Up button in the action bar.
actionBar.setDisplayHomeAsUpEnabled(true);
}
}
public boolean onCreateOptionsMenu(Menu menu)
{
getMenuInflater().inflate(R.menu.options, menu);
return super.onCreateOptionsMenu(menu);
}//End onCreateOptionMenu()
//If one of the options from the dropdown menu is selected the following will occur
public boolean onOptionsItemSelected(MenuItem item)
{
//Variable to hold id of selected menu option
int id = item.getItemId();
//If the settings option is selected, user will be re-directed to setting screen
if (id == R.id.action_settings)
{
Toast.makeText(SettingsActivity.this, "You are already in 'Settings'", Toast.LENGTH_LONG).show();
}//End if
//If the language option is selected, user will be re-directed to language screen
if (id == R.id.action_Language)
{
Intent intent = new Intent(SettingsActivity.this, MainActivity.class);
startActivity(intent);
}//End if
//If the help option is selected, user will be re-directed to help screen
if (id == R.id.action_help)
{
Intent intent = new Intent(SettingsActivity.this, UserHelp.class);
startActivity(intent);
}//End if
return super.onOptionsItemSelected(item);
}//End onOptionsItemSelected()
/**
* {#inheritDoc}
*/
#Override
public boolean onIsMultiPane() {
return isXLargeTablet(this);
}
/**
* {#inheritDoc}
*/
#Override
#TargetApi(Build.VERSION_CODES.HONEYCOMB)
public void onBuildHeaders(List<Header> target) {
loadHeadersFromResource(R.xml.pref_headers, target);
}
/**
* This method stops fragment injection in malicious applications.
* Make sure to deny any unknown fragments here.
*/
protected boolean isValidFragment(String fragmentName) {
return PreferenceFragment.class.getName().equals(fragmentName)
|| GeneralPreferenceFragment.class.getName().equals(fragmentName)
|| DataSyncPreferenceFragment.class.getName().equals(fragmentName)
|| NotificationPreferenceFragment.class.getName().equals(fragmentName);
}
/**
* This fragment shows general preferences only. It is used when the
* activity is showing a two-pane settings UI.
*/
#TargetApi(Build.VERSION_CODES.HONEYCOMB)
public static class GeneralPreferenceFragment extends PreferenceFragment {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.pref_general);
setHasOptionsMenu(true);
// Bind the summaries of EditText/List/Dialog/Ringtone preferences
// to their values. When their values change, their summaries are
// updated to reflect the new value, per the Android Design
// guidelines.
bindPreferenceSummaryToValue(findPreference("example_text"));
bindPreferenceSummaryToValue(findPreference("example_list"));
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
if (id == android.R.id.home) {
startActivity(new Intent(getActivity(), SettingsActivity.class));
return true;
}
return super.onOptionsItemSelected(item);
}
}
/**
* This fragment shows notification preferences only. It is used when the
* activity is showing a two-pane settings UI.
*/
#TargetApi(Build.VERSION_CODES.HONEYCOMB)
public static class NotificationPreferenceFragment extends PreferenceFragment {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.pref_notification);
setHasOptionsMenu(true);
// Bind the summaries of EditText/List/Dialog/Ringtone preferences
// to their values. When their values change, their summaries are
// updated to reflect the new value, per the Android Design
// guidelines.
bindPreferenceSummaryToValue(findPreference("notifications_new_message_ringtone"));
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
if (id == android.R.id.home) {
startActivity(new Intent(getActivity(), SettingsActivity.class));
return true;
}
return super.onOptionsItemSelected(item);
}
}
/**
* This fragment shows data and sync preferences only. It is used when the
* activity is showing a two-pane settings UI.
*/
#TargetApi(Build.VERSION_CODES.HONEYCOMB)
public static class DataSyncPreferenceFragment extends PreferenceFragment {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.pref_data_sync);
setHasOptionsMenu(true);
// Bind the summaries of EditText/List/Dialog/Ringtone preferences
// to their values. When their values change, their summaries are
// updated to reflect the new value, per the Android Design
// guidelines.
bindPreferenceSummaryToValue(findPreference("sync_frequency"));
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
if (id == android.R.id.home) {
startActivity(new Intent(getActivity(), SettingsActivity.class));
return true;
}
return super.onOptionsItemSelected(item);
}
}
}
change it programmatically
View view = findViewById(R.id.layout);
view.setBackgroundColor(getResources().getDrawable(R.drawable.YOUR_COLOR));
Define a new style in styles.xml:
<style name="PreferencesTheme" parent="android:Theme.Light">
<item name="android:background">#FFEAEAEA</item>
</style>
Or, if you are using AppCompat:
<style name="PreferencesTheme" parent="Theme.AppCompat.Light.DarkActionBar">
<item name="android:background">#color/background</item>
</style>
Then define the theme for your SettingsActivity in the AndroidManifest.xml:
<activity
android:name=".SettingsActivity"
android:label="#string/title_activity_settings"
android:theme="#style/PreferencesTheme"/>
Source: http://mobilemancer.com/2011/05/11/setting-a-background-image-on-a-preferenceactivity/
I'm looking for the best way nowadays to implement a Preference Screen for API 15+.
I have found other solutions including the Android Documentation for one of them:
PreferenceScreen and Settings guide
But there is no way to implement a custom layout I've found so far.
Custom layout is lost
my code so far:
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.design.widget.AppBarLayout
android:id="#+id/appbarlayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="#style/AppTheme.AppBarOverlay"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent">
<android.support.v7.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize">
</android.support.v7.widget.Toolbar>
</android.support.design.widget.AppBarLayout>
<android.support.v7.widget.AppCompatTextView
android:id="#+id/tv_activity_settings_nome_usuario"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Olááááááá"
app:layout_constraintBottom_toBottomOf="#id/appbarlayout"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"/>
<ListView
android:id="#android:id/list"
android:layout_width="match_parent"
android:layout_height="wrap_content">
</ListView>
</android.support.constraint.ConstraintLayout>
package com.irriger.cliente.ui.activity;
public class SettingsActivity extends AppCompatPreferenceActivity {
/**
* A preference value change listener that updates the preference's summary
* to reflect its new value.
*/
private static Preference.OnPreferenceChangeListener sBindPreferenceSummaryToValueListener = (preference, value) -> {
String stringValue = value.toString();
if (preference instanceof ListPreference) {
// For list preferences, look up the correct display value in
// the preference's 'entries' list.
ListPreference listPreference = (ListPreference) preference;
int index = listPreference.findIndexOfValue(stringValue);
// Set the summary to reflect the new value.
preference.setSummary(index >= 0 ? listPreference.getEntries()[index] : null);
} else if (preference instanceof RingtonePreference) {
// For ringtone preferences, look up the correct display value
// using RingtoneManager.
if (TextUtils.isEmpty(stringValue)) {
// Empty values correspond to 'silent' (no ringtone).
preference.setSummary(R.string.pref_ringtone_silent);
} else {
Ringtone ringtone = RingtoneManager.getRingtone(preference.getContext(), Uri.parse(stringValue));
if (ringtone == null) {
// Clear the summary if there was a lookup error.
preference.setSummary(null);
} else {
// Set the summary to reflect the new ringtone display
// name.
String name = ringtone.getTitle(preference.getContext());
preference.setSummary(name);
}
}
} else {
// For all other preferences, set the summary to the value's
// simple string representation.
preference.setSummary(stringValue);
}
return true;
};
/**
* Binds a preference's summary to its value. More specifically, when the
* preference's value is changed, its summary (line of text below the
* preference title) is updated to reflect the value. The summary is also
* immediately updated upon calling this method. The exact display format is
* dependent on the type of preference.
*
* #see #sBindPreferenceSummaryToValueListener
*/
private static void bindPreferenceSummaryToValue(Preference preference) {
// Set the listener to watch for value changes.
preference.setOnPreferenceChangeListener(sBindPreferenceSummaryToValueListener);
// Trigger the listener immediately with the preference's
// current value.
sBindPreferenceSummaryToValueListener.onPreferenceChange(preference,
PreferenceManager.getDefaultSharedPreferences(preference.getContext()).getString(preference.getKey(), ""));
}
#Override
protected void onCreate(Bundle savedInstanceState) {
if (BuildConfig.DEBUG) {
LogUtils.log("(onCreate) ");
}
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_settings);
setupActionBar();
}
/**
* Set up the {#link android.app.ActionBar}, if the API is available.
*/
private void setupActionBar() {
if (BuildConfig.DEBUG) {
LogUtils.log("(setupActionBar)");
}
Toolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
ActionBar actionBar = getSupportActionBar();
if (actionBar != null) {
// Show the Up button in the action bar.
actionBar.setDisplayHomeAsUpEnabled(true);
}
}
/**
* {#inheritDoc}
*/
#Override
public boolean onIsMultiPane() {
return isXLargeTablet(this);
}
/**
* Helper method to determine if the device has an extra-large screen. For
* example, 10" tablets are extra-large.
*/
private static boolean isXLargeTablet(Context context) {
if (BuildConfig.DEBUG) {
LogUtils.log("(isXLargeTablet)");
}
return (context.getResources()
.getConfiguration().screenLayout & Configuration.SCREENLAYOUT_SIZE_MASK) >= Configuration
.SCREENLAYOUT_SIZE_XLARGE;
}
/**
* {#inheritDoc}
*/
#Override
#TargetApi(Build.VERSION_CODES.HONEYCOMB)
public void onBuildHeaders(List<Header> target) {
if (BuildConfig.DEBUG) {
LogUtils.log("(onBuildHeaders)");
}
loadHeadersFromResource(R.xml.pref_headers, target);
}
/**
* This method stops fragment injection in malicious applications.
* Make sure to deny any unknown fragments here.
*/
protected boolean isValidFragment(String fragmentName) {
return PreferenceFragment.class.getName().equals(fragmentName) || GeneralPreferenceFragment.class.getName().equals(
fragmentName) || DataSyncPreferenceFragment.class.getName().equals(
fragmentName) || NotificationPreferenceFragment.class.getName().equals(
fragmentName) || RegiaoPreferenceFragment.class.getName().equals(fragmentName);
}
#Override
public boolean onPreferenceStartFragment(final PreferenceFragment caller, final Preference pref) {
if (BuildConfig.DEBUG) {
LogUtils.log("(onPreferenceStartFragment) ");
}
return super.onPreferenceStartFragment(caller, pref);
}
#SuppressWarnings("ConstantConditions")
#Override
public boolean onPreferenceTreeClick(final PreferenceScreen preferenceScreen, final Preference preference) {
super.onPreferenceTreeClick(preferenceScreen, preference);
if (preference != null) {
if (preference instanceof PreferenceScreen) {
if (((PreferenceScreen) preference).getDialog() != null) {
((PreferenceScreen) preference).getDialog().getWindow().getDecorView().setBackgroundDrawable(
this.getWindow().getDecorView().getBackground().getConstantState().newDrawable());
}
}
}
return false;
}
/**
* This fragment shows general preferences only. It is used when the
* activity is showing a two-pane settings UI.
*/
#TargetApi(Build.VERSION_CODES.HONEYCOMB)
public static class GeneralPreferenceFragment extends PreferenceFragment {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.pref_general);
setHasOptionsMenu(true);
// Bind the summaries of EditText/List/Dialog/Ringtone preferences
// to their values. When their values change, their summaries are
// updated to reflect the new value, per the Android Design
// guidelines.
bindPreferenceSummaryToValue(findPreference("example_text"));
bindPreferenceSummaryToValue(findPreference("example_list"));
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
if (id == android.R.id.home) {
startActivity(new Intent(getActivity(), SettingsActivity.class));
return true;
}
return super.onOptionsItemSelected(item);
}
}
/**
* This fragment shows notification preferences only. It is used when the
* activity is showing a two-pane settings UI.
*/
#TargetApi(Build.VERSION_CODES.HONEYCOMB)
public static class NotificationPreferenceFragment extends PreferenceFragment {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.pref_notification);
setHasOptionsMenu(true);
// Bind the summaries of EditText/List/Dialog/Ringtone preferences
// to their values. When their values change, their summaries are
// updated to reflect the new value, per the Android Design
// guidelines.
bindPreferenceSummaryToValue(findPreference("notifications_new_message_ringtone"));
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
if (id == android.R.id.home) {
startActivity(new Intent(getActivity(), SettingsActivity.class));
return true;
}
return super.onOptionsItemSelected(item);
}
}
/**
* This fragment shows data and sync preferences only. It is used when the
* activity is showing a two-pane settings UI.
*/
#TargetApi(Build.VERSION_CODES.HONEYCOMB)
public static class DataSyncPreferenceFragment extends PreferenceFragment {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.pref_data_sync);
setHasOptionsMenu(true);
// Bind the summaries of EditText/List/Dialog/Ringtone preferences
// to their values. When their values change, their summaries are
// updated to reflect the new value, per the Android Design
// guidelines.
bindPreferenceSummaryToValue(findPreference("sync_frequency"));
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
if (id == android.R.id.home) {
startActivity(new Intent(getActivity(), SettingsActivity.class));
return true;
}
return super.onOptionsItemSelected(item);
}
}
}
EDIT So, what I want to achieve is a screen more or less like this:
A good example would be WhatsApp Settings where you have your picture with "preference headers"
The application i'm developing will run on a tablet which is going to be placed inside a "cage" to prevent the user from removing it.
This "cage" will recreate a Kiosk mode; the android buttons Bar with the back and the home button will not be physical accessible by the user.
In the Main activities and in the fragment i managed to "go back" by calling onBackPressed() within the OnClickListener of some buttons.
Now the problem is that i have to add a settings activity, this kind of activity doesn't use normal layouts but PreferenceScreen instead.
I can't figure out how to action onBackPressed() if the only things that i can show in the layout are the prefereces.
I tryed adding a switchpreference called GoBack and creating an handler with refresh continuisly and check if GoBack preference is True, in that case i would set it to false and i would trigger onBackPressed(); but it didn't work, Go Back didn't change, the app crashed and i wasn't able to make it working.
Here's the SettingActivity code (The android studio one)
public class SettingsActivity extends AppCompatPreferenceActivity {
private static Preference.OnPreferenceChangeListener sBindPreferenceSummaryToValueListener = new Preference.OnPreferenceChangeListener() {
#Override
public boolean onPreferenceChange(Preference preference, Object value) {
String stringValue = value.toString();
if (preference instanceof ListPreference) {
// For list preferences, look up the correct display value in
// the preference's 'entries' list.
ListPreference listPreference = (ListPreference) preference;
int index = listPreference.findIndexOfValue(stringValue);
// Set the summary to reflect the new value.
preference.setSummary(
index >= 0
? listPreference.getEntries()[index]
: null);
} else if (preference instanceof RingtonePreference) {
// For ringtone preferences, look up the correct display value
// using RingtoneManager.
if (TextUtils.isEmpty(stringValue)) {
// Empty values correspond to 'silent' (no ringtone).
preference.setSummary(R.string.pref_ringtone_silent);
} else {
Ringtone ringtone = RingtoneManager.getRingtone(
preference.getContext(), Uri.parse(stringValue));
if (ringtone == null) {
// Clear the summary if there was a lookup error.
preference.setSummary(null);
} else {
// Set the summary to reflect the new ringtone display
// name.
String name = ringtone.getTitle(preference.getContext());
preference.setSummary(name);
}
}
} else {
// For all other preferences, set the summary to the value's
// simple string representation.
preference.setSummary(stringValue);
}
return true;
}
};
/**
* Helper method to determine if the device has an extra-large screen. For
* example, 10" tablets are extra-large.
*/
private static boolean isXLargeTablet(Context context) {
return (context.getResources().getConfiguration().screenLayout
& Configuration.SCREENLAYOUT_SIZE_MASK) >= Configuration.SCREENLAYOUT_SIZE_XLARGE;
}
/**
* Binds a preference's summary to its value. More specifically, when the
* preference's value is changed, its summary (line of text below the
* preference title) is updated to reflect the value. The summary is also
* immediately updated upon calling this method. The exact display format is
* dependent on the type of preference.
*
* #see #sBindPreferenceSummaryToValueListener
*/
private static void bindPreferenceSummaryToValue(Preference preference) {
// Set the listener to watch for value changes.
preference.setOnPreferenceChangeListener(sBindPreferenceSummaryToValueListener);
// Trigger the listener immediately with the preference's
// current value.
try {
sBindPreferenceSummaryToValueListener.onPreferenceChange(preference,
PreferenceManager
.getDefaultSharedPreferences(preference.getContext())
.getString(preference.getKey(), ""));
}
catch (Exception e)
{
try {
sBindPreferenceSummaryToValueListener.onPreferenceChange(preference,
PreferenceManager
.getDefaultSharedPreferences(preference.getContext())
.getBoolean(preference.getKey(),false));
}
catch (Exception ex)
{
Log.e("Impostazioni","Impossibile eseguire Sett.Binding di "+preference.getKey());
}
}
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setupActionBar();
}
/**
* Set up the {#link android.app.ActionBar}, if the API is available.
*/
private void setupActionBar() {
ActionBar actionBar = getSupportActionBar();
if (actionBar != null) {
// Show the Up button in the action bar.
actionBar.setDisplayHomeAsUpEnabled(true);
}
}
#Override
public boolean onMenuItemSelected(int featureId, MenuItem item) {
int id = item.getItemId();
if (id == android.R.id.home) {
if (!super.onMenuItemSelected(featureId, item)) {
NavUtils.navigateUpFromSameTask(this);
}
return true;
}
return super.onMenuItemSelected(featureId, item);
}
/**
* {#inheritDoc}
*/
#Override
public boolean onIsMultiPane() {
return isXLargeTablet(this);
}
/**
* {#inheritDoc}
*/
#Override
#TargetApi(Build.VERSION_CODES.HONEYCOMB)
public void onBuildHeaders(List<Header> target) {
loadHeadersFromResource(R.xml.pref_headers, target);
}
/**
* This method stops fragment injection in malicious applications.
* Make sure to deny any unknown fragments here.
*/
protected boolean isValidFragment(String fragmentName) {
return PreferenceFragment.class.getName().equals(fragmentName)
|| GeneralPreferenceFragment.class.getName().equals(fragmentName)
|| DataSyncPreferenceFragment.class.getName().equals(fragmentName)
|| NotificationPreferenceFragment.class.getName().equals(fragmentName);
}
/**
* This fragment shows general preferences only. It is used when the
* activity is showing a two-pane settings UI.
*/
#TargetApi(Build.VERSION_CODES.HONEYCOMB)
public static class GeneralPreferenceFragment extends PreferenceFragment {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.pref_general);
setHasOptionsMenu(true);
// Bind the summaries of EditText/List/Dialog/Ringtone preferences
// to their values. When their values change, their summaries are
// updated to reflect the new value, per the Android Design
// guidelines.
bindPreferenceSummaryToValue(findPreference("PassWordImpostazioni"));
//bindPreferenceSummaryToValue(findPreference("example_list"));
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
if (id == android.R.id.home) {
startActivity(new Intent(getActivity(), SettingsActivity.class));
return true;
}
return super.onOptionsItemSelected(item);
}
}
/**
* This fragment shows notification preferences only. It is used when the
* activity is showing a two-pane settings UI.
*/
#TargetApi(Build.VERSION_CODES.HONEYCOMB)
public static class NotificationPreferenceFragment extends PreferenceFragment {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.pref_notification);
setHasOptionsMenu(true);
// Bind the summaries of EditText/List/Dialog/Ringtone preferences
// to their values. When their values change, their summaries are
// updated to reflect the new value, per the Android Design
// guidelines.
/*bindPreferenceSummaryToValue(findPreference("LedBattutaPorta"));
bindPreferenceSummaryToValue(findPreference("SpoilerPosteriore"));
bindPreferenceSummaryToValue(findPreference("LuciBianche"));
bindPreferenceSummaryToValue(findPreference("Scalino"));
bindPreferenceSummaryToValue(findPreference("Webasto"));
bindPreferenceSummaryToValue(findPreference("Stufa220V"));*/
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
if (id == android.R.id.home) {
startActivity(new Intent(getActivity(), SettingsActivity.class));
return true;
}
return super.onOptionsItemSelected(item);
}
}
/**
* This fragment shows data and sync preferences only. It is used when the
* activity is showing a two-pane settings UI.
*/
#TargetApi(Build.VERSION_CODES.HONEYCOMB)
public static class DataSyncPreferenceFragment extends PreferenceFragment {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.pref_data_sync);
setHasOptionsMenu(true);
// Bind the summaries of EditText/List/Dialog/Ringtone preferences
// to their values. When their values change, their summaries are
// updated to reflect the new value, per the Android Design
// guidelines.
bindPreferenceSummaryToValue(findPreference("sync_frequency"));
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
if (id == android.R.id.home) {
startActivity(new Intent(getActivity(), SettingsActivity.class));
return true;
}
return super.onOptionsItemSelected(item);
}
}
}
Here's the PreferenceScreen XML
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
<PreferenceCategory
android:title="OPT. Luci"
android:key="OptLuci">
<SwitchPreference
android:defaultValue="false"
android:key="LedBattutaPorta"
android:title="Pulsante Disabilitazione Led Battuta Porta" />
<SwitchPreference
android:defaultValue="false"
android:key="SpoilerPosteriore"
android:title="Pulsante Disabilitazione Spoiler Posteriore" />
<SwitchPreference
android:defaultValue="false"
android:key="LuciBianche"
android:title="Pulsante Disabilitazione Luci Bianche" />
</PreferenceCategory>
<PreferenceCategory
android:title="OPT. Servizi"
android:key="OptServizi">
<SwitchPreference
android:defaultValue="false"
android:key="Scalino"
android:title="Pulsante Disabilitazione Scalino" />
</PreferenceCategory>
<PreferenceCategory
android:title="OPT. Clima"
android:key="OptClima">
<SwitchPreference
android:defaultValue="false"
android:key="Webasto"
android:title="Webasto" />
<SwitchPreference
android:defaultValue="false"
android:key="Stufa220V"
android:title="Stufa 220V" />
</PreferenceCategory>
<PreferenceCategory
android:title="OPT. Vano Sanitario"
android:key="OptVanoSanitario">
<SwitchPreference
android:defaultValue="false"
android:key="Bombola1"
android:title="Presenza Bombola 1" />
<SwitchPreference
android:defaultValue="false"
android:key="Bombola2"
android:title="Presenza Bombola 2" />
</PreferenceCategory>
You can keep a button and in the click of the button, call:
finishActivity();
This will force a return to previous activity in your activity stack.
1.Back Button in Activity
Copy the layout from
com.android.internal.R.layout.preference_list_content_single
Add your back button and overwrite the onCreate to set your new layout
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(yourLayout)
}
2.Back Button in Fragment Layout
Copy the layout from
com.android.internal.R.layout.preference_list_fragment
And add your back button
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container,
#Nullable Bundle savedInstanceState) {
TypedArray a = getActivity().obtainStyledAttributes(null,
com.android.internal.R.styleable.PreferenceFragment,
com.android.internal.R.attr.preferenceFragmentStyle,
0);
int yourLayout = R.layout.your_layout; //put your custom layout here
yourLayout = a.getResourceId(com.android.internal.R.styleable.PreferenceFragment_layout,
yourLayout);
a.recycle();
return inflater.inflate(yourLayout, container, false);
}
Register an OnClickListener to the button and call onBackPressed() of the Activity which will trigger the back action (finish() will destroy the activity, which might not be useful if you want to navigate back to an earlier fragment)
Edit: I haven´t tested it, but it should work
Problem solved in this way:
I made another custom theme just for the settings in which i show the action bar with the back button.
It works fine, thanks to everybody :)
I'm working in a project in Android Studio with min SDK set by 10. I just added a Settings Activity from Gallery and it works well in a phone with API 17, but not in other phone with API 10.
What I think strange is the Settings Activity is available from Gallery, it is supposed to be compatible with API 10 that I'm working, and other activities templates like FullScreen Activity is not available and shows a message "Selected activity template has a minimum of SDK level of 11"
Here is the code from Settings Activity template:
public class SettingsActivity extends AppCompatPreferenceActivity {
/**
* A preference value change listener that updates the preference's summary
* to reflect its new value.
*/
private static Preference.OnPreferenceChangeListener sBindPreferenceSummaryToValueListener = new Preference.OnPreferenceChangeListener() {
#Override
public boolean onPreferenceChange(Preference preference, Object value) {
String stringValue = value.toString();
if (preference instanceof ListPreference) {
// For list preferences, look up the correct display value in
// the preference's 'entries' list.
ListPreference listPreference = (ListPreference) preference;
int index = listPreference.findIndexOfValue(stringValue);
// Set the summary to reflect the new value.
preference.setSummary(
index >= 0
? listPreference.getEntries()[index]
: null);
} else if (preference instanceof RingtonePreference) {
// For ringtone preferences, look up the correct display value
// using RingtoneManager.
if (TextUtils.isEmpty(stringValue)) {
// Empty values correspond to 'silent' (no ringtone).
preference.setSummary(R.string.pref_ringtone_silent);
} else {
Ringtone ringtone = RingtoneManager.getRingtone(
preference.getContext(), Uri.parse(stringValue));
if (ringtone == null) {
// Clear the summary if there was a lookup error.
preference.setSummary(null);
} else {
// Set the summary to reflect the new ringtone display
// name.
String name = ringtone.getTitle(preference.getContext());
preference.setSummary(name);
}
}
} else {
// For all other preferences, set the summary to the value's
// simple string representation.
preference.setSummary(stringValue);
}
return true;
}
};
/**
* Helper method to determine if the device has an extra-large screen. For
* example, 10" tablets are extra-large.
*/
private static boolean isXLargeTablet(Context context) {
return (context.getResources().getConfiguration().screenLayout
& Configuration.SCREENLAYOUT_SIZE_MASK) >= Configuration.SCREENLAYOUT_SIZE_XLARGE;
}
/**
* Binds a preference's summary to its value. More specifically, when the
* preference's value is changed, its summary (line of text below the
* preference title) is updated to reflect the value. The summary is also
* immediately updated upon calling this method. The exact display format is
* dependent on the type of preference.
*
* #see #sBindPreferenceSummaryToValueListener
*/
private static void bindPreferenceSummaryToValue(Preference preference) {
// Set the listener to watch for value changes.
preference.setOnPreferenceChangeListener(sBindPreferenceSummaryToValueListener);
// Trigger the listener immediately with the preference's
// current value.
sBindPreferenceSummaryToValueListener.onPreferenceChange(preference,
PreferenceManager
.getDefaultSharedPreferences(preference.getContext())
.getString(preference.getKey(), ""));
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setupActionBar();
}
/**
* Set up the {#link android.app.ActionBar}, if the API is available.
*/
private void setupActionBar() {
ActionBar actionBar = getSupportActionBar();
if (actionBar != null) {
// Show the Up button in the action bar.
actionBar.setDisplayHomeAsUpEnabled(true);
}
}
/**
* {#inheritDoc}
*/
#Override
public boolean onIsMultiPane() {
return isXLargeTablet(this);
}
/**
* {#inheritDoc}
*/
#Override
#TargetApi(Build.VERSION_CODES.HONEYCOMB)
public void onBuildHeaders(List<Header> target) {
loadHeadersFromResource(R.xml.pref_headers, target);
}
/**
* This method stops fragment injection in malicious applications.
* Make sure to deny any unknown fragments here.
*/
protected boolean isValidFragment(String fragmentName) {
return PreferenceFragment.class.getName().equals(fragmentName)
|| GeneralPreferenceFragment.class.getName().equals(fragmentName)
|| DataSyncPreferenceFragment.class.getName().equals(fragmentName)
|| NotificationPreferenceFragment.class.getName().equals(fragmentName);
}
/**
* This fragment shows general preferences only. It is used when the
* activity is showing a two-pane settings UI.
*/
#TargetApi(Build.VERSION_CODES.HONEYCOMB)
public static class GeneralPreferenceFragment extends PreferenceFragment {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.pref_general);
setHasOptionsMenu(true);
// Bind the summaries of EditText/List/Dialog/Ringtone preferences
// to their values. When their values change, their summaries are
// updated to reflect the new value, per the Android Design
// guidelines.
bindPreferenceSummaryToValue(findPreference("example_text"));
bindPreferenceSummaryToValue(findPreference("example_list"));
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
if (id == android.R.id.home) {
startActivity(new Intent(getActivity(), SettingsActivity.class));
return true;
}
return super.onOptionsItemSelected(item);
}
}
/**
* This fragment shows notification preferences only. It is used when the
* activity is showing a two-pane settings UI.
*/
#TargetApi(Build.VERSION_CODES.HONEYCOMB)
public static class NotificationPreferenceFragment extends PreferenceFragment {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.pref_notification);
setHasOptionsMenu(true);
// Bind the summaries of EditText/List/Dialog/Ringtone preferences
// to their values. When their values change, their summaries are
// updated to reflect the new value, per the Android Design
// guidelines.
bindPreferenceSummaryToValue(findPreference("notifications_new_message_ringtone"));
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
if (id == android.R.id.home) {
startActivity(new Intent(getActivity(), SettingsActivity.class));
return true;
}
return super.onOptionsItemSelected(item);
}
}
/**
* This fragment shows data and sync preferences only. It is used when the
* activity is showing a two-pane settings UI.
*/
#TargetApi(Build.VERSION_CODES.HONEYCOMB)
public static class DataSyncPreferenceFragment extends PreferenceFragment {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.pref_data_sync);
setHasOptionsMenu(true);
// Bind the summaries of EditText/List/Dialog/Ringtone preferences
// to their values. When their values change, their summaries are
// updated to reflect the new value, per the Android Design
// guidelines.
bindPreferenceSummaryToValue(findPreference("sync_frequency"));
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
if (id == android.R.id.home) {
startActivity(new Intent(getActivity(), SettingsActivity.class));
return true;
}
return super.onOptionsItemSelected(item);
}
}
}
The class SettingsActivity inherits from AppCompatPreferenceActivity which extends from PreferenceActivity. According to this reference PreferenceActivity, it should work for API 10.
So what's wrong from the template class that is not working in my old phone?
Should I use this template to make my SettingsActivity or just create my own from scratch?
Thanks!
I seem to have a problem passing data gotten in an Activity to a Fragment. The data does not appear in the listfragment!
Here is my listfragmentactivity. I reinstantiate the fragment every time I add an item to the list aka bundle an item and use the constructor in the new fragment to do it.
package com.example.sample;
import android.content.Intent;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentTransaction;
import android.widget.Toast;
import com.actionbarsherlock.app.ActionBar;
import com.actionbarsherlock.app.ActionBar.Tab;
import com.actionbarsherlock.app.SherlockFragmentActivity;
import com.actionbarsherlock.view.Menu;
import com.actionbarsherlock.view.MenuItem;
/**
* An activity representing a list of Courses. This activity has different
* presentations for handset and tablet-size devices. On handsets, the activity
* presents a list of items, which when touched, lead to a
* {#link CourseDetailActivity} representing item details. On tablets, the
* activity presents the list of items and item details side-by-side using two
* vertical panes.
* <p>
* The activity makes heavy use of fragments. The list of items is a
* {#link CourseListFragment} and the item details (if present) is a
* {#link CourseDetailFragment}.
* <p>
* This activity also implements the required
* {#link CourseListFragment.Callbacks} interface to listen for item selections.
*/
public class CourseListActivity extends SherlockFragmentActivity implements
CourseListFragment.Callbacks {
CourseListFragment listFrag;
public static String courseName;
private static final int REQUEST_CODE = 10;
/**
* Whether or not the activity is in two-pane mode, i.e. running on a tablet
* device.
*/
private boolean mTwoPane;
private boolean once = true;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_course_list);
if (findViewById(R.id.course_detail_container) != null) {
// The detail container view will be present only in the
// large-screen layouts (res/values-large and
// res/values-sw600dp). If this view is present, then the
// activity should be in two-pane mode.
mTwoPane = true;
// In two-pane mode, list items should be given the
// 'activated' state when touched.
listFrag = ((CourseListFragment) getSupportFragmentManager().findFragmentById(
R.id.course_list));
listFrag.setActivateOnItemClick(true);
}
// TODO: If exposing deep links into your app, handle intents here.
}
/**
* Callback method from {#link CourseListFragment.Callbacks} indicating that
* the item with the given ID was selected.
*/
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getSupportMenuInflater().inflate(R.menu.activity_main, menu);
return true;
}
public boolean onOptionsItemSelected(MenuItem item) {
boolean bool;
switch (item.getItemId()) {
case R.id.add_course:
Intent intent = new Intent(this, CourseAddActivity.class);
startActivityForResult(intent, REQUEST_CODE);
bool = true;
default:
bool = super.onOptionsItemSelected(item);
}
return bool;
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (resultCode == RESULT_OK && requestCode == REQUEST_CODE) {
if (data.hasExtra("courseName")) {
courseName = data.getExtras().getString("courseName");
Bundle args = new Bundle();
args.putString("courseKey", courseName);
listFrag = new CourseListFragment(args);
}
}
}
#Override
public void onItemSelected(String id) {
if (mTwoPane) {
// In two-pane mode, show the detail view in this activity by
// adding or replacing the detail fragment using a
// fragment transaction.
if (once) {
ActionBar actionBar = getSupportActionBar();
actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
// initiating both tabs and set text to it.
ActionBar.Tab assignTab = actionBar.newTab().setText(
"Assignments");
ActionBar.Tab schedTab = actionBar.newTab().setText("Schedule");
ActionBar.Tab contactTab = actionBar.newTab()
.setText("Contact");
// Create three fragments to display content
Fragment assignFragment = new Assignments();
Fragment schedFragment = new Schedule();
Fragment contactFragment = new Contact();
assignTab.setTabListener(new MyTabsListener(assignFragment));
schedTab.setTabListener(new MyTabsListener(schedFragment));
contactTab.setTabListener(new MyTabsListener(contactFragment));
actionBar.addTab(assignTab);
actionBar.addTab(schedTab);
actionBar.addTab(contactTab);
once = false;
}
} else {
// In single-pane mode, simply start the detail activity
// for the selected item ID.
Intent detailIntent = new Intent(this, CourseDetailActivity.class);
startActivity(detailIntent);
}
}
class MyTabsListener implements ActionBar.TabListener {
public Fragment fragment;
public MyTabsListener(Fragment fragment) {
this.fragment = fragment;
}
#Override
public void onTabReselected(Tab tab, FragmentTransaction ft) {
}
#Override
public void onTabSelected(Tab tab, FragmentTransaction ft) {
ft.replace(R.id.course_detail_container, fragment);
}
#Override
public void onTabUnselected(Tab tab, FragmentTransaction ft) {
ft.remove(fragment);
}
}
}
And here is my ListFragment, where I create two constructors, one which accepts arguments.
package com.example.sample;
import java.util.ArrayList;
import android.app.Activity;
import android.os.Build;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import android.widget.Toast;
import com.actionbarsherlock.app.SherlockListFragment;
/**
* A list fragment representing a list of Courses. This fragment also supports
* tablet devices by allowing list items to be given an 'activated' state upon
* selection. This helps indicate which item is currently being viewed in a
* {#link CourseDetailFragment}.
* <p>
* Activities containing this fragment MUST implement the {#link Callbacks}
* interface.
*/
public class CourseListFragment extends SherlockListFragment {
private static String courseName;
ArrayList<String> courseItems;
ArrayAdapter<String> adapter;
/**
* The serialization (saved instance state) Bundle key representing the
* activated item position. Only used on tablets.
*/
private static final String STATE_ACTIVATED_POSITION = "activated_position";
/**
* The fragment's current callback object, which is notified of list item
* clicks.
*/
private Callbacks mCallbacks = sDummyCallbacks;
/**
* The current activated item position. Only used on tablets.
*/
private int mActivatedPosition = ListView.INVALID_POSITION;
/**
* A callback interface that all activities containing this fragment must
* implement. This mechanism allows activities to be notified of item
* selections.
*/
public interface Callbacks {
/**
* Callback for when an item has been selected.
*/
public void onItemSelected(String id);
}
/**
* A dummy implementation of the {#link Callbacks} interface that does
* nothing. Used only when this fragment is not attached to an activity.
*/
private static Callbacks sDummyCallbacks = new Callbacks() {
#Override
public void onItemSelected(String id) {
}
};
/**
* Mandatory empty constructor for the fragment manager to instantiate the
* fragment (e.g. upon screen orientation changes).
*/
public CourseListFragment() {
}
public CourseListFragment(Bundle args) {
courseName = args.get("courseKey").toString();
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
courseItems = new ArrayList<String>();
adapter = new ArrayAdapter<String>(getActivity(),
android.R.layout.simple_list_item_1, courseItems);
// TODO: replace with a real list adapter.
int layout = (Build.VERSION.SDK_INT >= 11) ? android.R.layout.simple_list_item_activated_1
: android.R.layout.simple_list_item_1;
setListAdapter(adapter);
}
#Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
// Restore the previously serialized activated item position.
if (savedInstanceState != null
&& savedInstanceState.containsKey(STATE_ACTIVATED_POSITION)) {
setActivatedPosition(savedInstanceState
.getInt(STATE_ACTIVATED_POSITION));
courseItems.add(courseName);
adapter.notifyDataSetChanged();
}
}
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
// Activities containing this fragment must implement its callbacks.
if (!(activity instanceof Callbacks)) {
throw new IllegalStateException(
"Activity must implement fragment's callbacks.");
}
mCallbacks = (Callbacks) activity;
}
#Override
public void onDetach() {
super.onDetach();
// Reset the active callbacks interface to the dummy implementation.
mCallbacks = sDummyCallbacks;
}
#Override
public void onListItemClick(ListView listView, View view, int position,
long id) {
super.onListItemClick(listView, view, position, id);
// Notify the active callbacks interface (the activity, if the
// fragment is attached to one) that an item has been selected.
}
#Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
if (mActivatedPosition != ListView.INVALID_POSITION) {
// Serialize and persist the activated item position.
outState.putInt(STATE_ACTIVATED_POSITION, mActivatedPosition);
}
}
/**
* Turns on activate-on-click mode. When this mode is on, list items will be
* given the 'activated' state when touched.
*/
public void setActivateOnItemClick(boolean activateOnItemClick) {
// When setting CHOICE_MODE_SINGLE, ListView will automatically
// give items the 'activated' state when touched.
getListView().setChoiceMode(
activateOnItemClick ? ListView.CHOICE_MODE_SINGLE
: ListView.CHOICE_MODE_NONE);
}
private void setActivatedPosition(int position) {
if (position == ListView.INVALID_POSITION) {
getListView().setItemChecked(mActivatedPosition, false);
} else {
getListView().setItemChecked(position, true);
}
mActivatedPosition = position;
}
}
Any help at all is much appreciated!
Thank You!
If you re-instantiate like this, class variables of CourseListFragment will be destroyed each time you call
listFrag = new CourseListFragment(args);
You should create a method in CourseListFragment to add a course name without destroying the current fragment:
public void addCourse(String courseName) {
courseItems.add(courseName);
adapter.notifyDataSetChanged();
}
And in your activity:
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (resultCode == RESULT_OK && requestCode == REQUEST_CODE) {
if (data.hasExtra("courseName")) {
courseName = data.getExtras().getString("courseName");
listFrag.addCourse(courseName);
}
}
}