/**
* Copyright 2010-present Facebook.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.facebook.samples.switchuser;
import android.content.Context;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.support.v4.app.ListFragment;
import android.view.*;
import android.widget.*;
import com.facebook.model.GraphUser;
import com.facebook.widget.ProfilePictureView;
import com.facebook.SessionLoginBehavior;
import java.util.ArrayList;
import java.util.Arrays;
public class SettingsFragment extends ListFragment {
public static final String TAG = "SettingsFragment";
private static final String CURRENT_SLOT_KEY = "CurrentSlot";
private SlotManager slotManager;
private OnSlotChangedListener slotChangedListener;
private boolean hasPendingNotifySlotChanged;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
slotManager = new SlotManager();
slotManager.restore(
getActivity(),
savedInstanceState != null ?
savedInstanceState.getInt(CURRENT_SLOT_KEY, SlotManager.NO_SLOT) :
SlotManager.NO_SLOT);
ArrayList<Slot> slotList = new ArrayList<Slot>(
Arrays.asList(slotManager.getAllSlots()));
setListAdapter(new SlotAdapter(slotList));
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup parent, Bundle savedInstanceState) {
View view = super.onCreateView(inflater, parent, savedInstanceState);
registerForContextMenu(view.findViewById(android.R.id.list));
return view;
}
@Override
public void onCreateContextMenu(ContextMenu menu, View view, ContextMenu.ContextMenuInfo menuInfo) {
super.onCreateContextMenu(menu, view, menuInfo);
getActivity().getMenuInflater().inflate(R.menu.context_settings, menu);
}
@Override
public void onListItemClick(ListView l, View view, int position, long id) {
slotManager.toggleSlot(position);
}
@Override
public boolean onContextItemSelected(MenuItem item) {
AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) item.getMenuInfo();
SlotAdapter adapter = (SlotAdapter) getListAdapter();
Slot slot = adapter.getItem(info.position);
switch (item.getItemId()) {
case R.id.menu_item_clear_slot:
if (slot.getUserId() != null) {
// Clear out data that this app stored in the cache
// Not calling Session.closeAndClearTokenInformation() because we have additional
// data stored in the cache.
slot.clear();
if (slot == slotManager.getSelectedSlot()) {
slotManager.toggleSlot(info.position);
}
updateListView();
}
return true;
}
return super.onContextItemSelected(item);
}
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putInt(CURRENT_SLOT_KEY, slotManager.getSelectedSlotNumber());
}
public void setSlotChangedListener(OnSlotChangedListener listener) {
slotChangedListener = listener;
if (listener != null && hasPendingNotifySlotChanged) {
notifySlotChanged();
hasPendingNotifySlotChanged = false;
}
}
public void updateViewForUser(GraphUser user) {
if (slotManager == null) {
// Fragment has not had onCreate called yet.
return;
}
if (user != null) {
Slot s = slotManager.getSelectedSlot();
if (s != null) {
s.update(user);
}
} else {
// If the user is null, then there isn't an actively selected
// user. This can happen if the user cancelled a login. So make sure that
// SlotManager is updated properly.
slotManager.setSelectedSlotNumber(SlotManager.NO_SLOT);
}
updateListView();
}
private void notifySlotChanged() {
OnSlotChangedListener listener = slotChangedListener;
if (listener != null) {
Slot newSlot = slotManager.getSelectedSlot();
listener.onSlotChanged(newSlot);
} else {
hasPendingNotifySlotChanged = true;
}
}
private void updateListView() {
SlotAdapter adapter = (SlotAdapter) getListAdapter();
adapter.notifyDataSetChanged();
}
public interface OnSlotChangedListener {
void onSlotChanged(Slot newSlot);
}
private class SlotAdapter extends ArrayAdapter<Slot> {
public SlotAdapter(ArrayList<Slot> slots) {
super(getActivity(), android.R.layout.simple_list_item_1, slots);
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
if (null == convertView) {
convertView = getActivity().getLayoutInflater()
.inflate(R.layout.list_item_user, null);
}
Slot slot = getItem(position);
String userName = slot.getUserName();
if (userName == null) {
userName = getString(R.string.empty_slot);
}
ProfilePictureView profilePictureView = (ProfilePictureView) convertView.findViewById(
R.id.slotPic);
profilePictureView.setCropped(true);
profilePictureView.setProfileId(slot.getUserId());
TextView userNameTextView = (TextView) convertView.findViewById(
R.id.slotUserName);
userNameTextView.setText(userName);
CheckBox currentUserCheckBox = (CheckBox) convertView.findViewById(
R.id.currentUserIndicator);
currentUserCheckBox.setChecked(slotManager.getSelectedSlot() == slot);
return convertView;
}
}
private class SlotManager {
static final int NO_SLOT = -1;
private final static int MAX_SLOTS = 4;
private static final String SETTINGS_CURRENT_SLOT_KEY = "CurrentSlot";
private static final String SETTINGS_NAME = "UserManagerSettings";
private SharedPreferences settings;
private int selectedSlotNumber = NO_SLOT;
private Slot[] slots;
void restore(Context context, int oldSelectedSlot) {
if (context == null) {
throw new IllegalArgumentException("context cannot be null");
}
Context applicationContext = context.getApplicationContext();
applicationContext = (applicationContext == null) ? context : applicationContext;
slots = new Slot[MAX_SLOTS];
for (int i = 0; i < MAX_SLOTS; i++) {
SessionLoginBehavior loginBehavior = (i == 0) ?
SessionLoginBehavior.SSO_WITH_FALLBACK :
SessionLoginBehavior.SUPPRESS_SSO;
slots[i] = new Slot(applicationContext, i, loginBehavior);
}
// Restore the last known state from when the app ran last.
settings = applicationContext.getSharedPreferences(SETTINGS_NAME, Context.MODE_PRIVATE);
int savedSlotNumber = settings.getInt(SETTINGS_CURRENT_SLOT_KEY, NO_SLOT);
if (savedSlotNumber != NO_SLOT && savedSlotNumber != oldSelectedSlot) {
// This will trigger the full flow of creating and opening the right session
toggleSlot(savedSlotNumber);
} else {
// We already knew which slot was selected. So don't notify that a new slot was
// selected since that will close out the old session and recreate a new one. And
// doing so will have the effect of clearing out state like the profile pic.
setSelectedSlotNumber(savedSlotNumber);
}
}
void toggleSlot(int slot) {
validateSlot(slot);
if (slot == selectedSlotNumber) {
setSelectedSlotNumber(NO_SLOT);
} else {
setSelectedSlotNumber(slot);
}
notifySlotChanged();
}
Slot getSelectedSlot() {
if (selectedSlotNumber == NO_SLOT) {
return null;
} else {
return getSlot(selectedSlotNumber);
}
}
int getSelectedSlotNumber() {
return selectedSlotNumber;
}
Slot[] getAllSlots() {
return slots;
}
Slot getSlot(int slot) {
validateSlot(slot);
return slots[slot];
}
private void setSelectedSlotNumber(int slot) {
// Store the selected slot number for when the app is closed and restarted
settings.edit().putInt(SETTINGS_CURRENT_SLOT_KEY, slot).commit();
selectedSlotNumber = slot;
}
private void validateSlot(int slot) {
if (slot <= NO_SLOT || slot >= MAX_SLOTS) {
throw new IllegalArgumentException(
String.format("Choose a slot between 0 and %d inclusively", MAX_SLOTS-1));
}
}
}
}