package com.zhuinden.simplestackdemonestedstack.util; import android.content.Context; import com.zhuinden.servicetree.ServiceTree; import com.zhuinden.simplestack.Backstack; import com.zhuinden.simplestack.BackstackManager; import com.zhuinden.simplestack.Bundleable; import com.zhuinden.simplestack.StateChange; import com.zhuinden.simplestack.navigator.Navigator; import com.zhuinden.simplestackdemonestedstack.application.Key; import com.zhuinden.statebundle.StateBundle; import java.util.ArrayList; import java.util.List; public class NestSupportServiceManager { public static final String SERVICE_MANAGER = "SERVICE_MANAGER"; public static NestSupportServiceManager get(Context context) { //noinspection ResourceType return (NestSupportServiceManager) context.getSystemService(SERVICE_MANAGER); } private final ServiceTree serviceTree; private final Object rootKey; private final List<Object> activeKeys = new ArrayList<>(); public NestSupportServiceManager(ServiceTree serviceTree, Object rootKey) { this.serviceTree = serviceTree; this.rootKey = rootKey; } public static final String SERVICE_STATES = "SERVICE_BUNDLE"; private static final String TAG = "NestServiceManager"; public StateBundle persistStates() { StateBundle serviceStates = new StateBundle(); serviceTree.traverseTree(ServiceTree.Walk.PRE_ORDER, (node, cancellationToken) -> { StateBundle keyBundle = new StateBundle(); for(ServiceTree.Node.Entry entry : node.getBoundServices()) { if(entry.getService() instanceof Bundleable) { keyBundle.putParcelable(entry.getName(), ((Bundleable) entry.getService()).toBundle()); } } serviceStates.putParcelable(node.getKey().toString(), keyBundle); }); return serviceStates; } public void setupServices(StateChange stateChange) { setupServices(stateChange, false); } public void setupServices(StateChange stateChange, boolean isFromCompositeKey) { StateBundle states = serviceTree.getNode(rootKey).getService(SERVICE_STATES); for(Object _previousKey : stateChange.getPreviousState()) { Key previousKey = (Key) _previousKey; if(!stateChange.getNewState().contains(previousKey)) { activeKeys.remove(previousKey); if(!isFromCompositeKey) { ServiceTree.Node previousNode = serviceTree.getNode(previousKey); if(states != null) { serviceTree.traverseSubtree(previousNode, ServiceTree.Walk.POST_ORDER, (node, cancellationToken) -> { states.remove(node.getKey().toString()); }); } serviceTree.removeNodeAndChildren(previousNode); } } } for(Object _newKey : stateChange.getNewState()) { Key newKey = (Key) _newKey; activeKeys.remove(newKey); if(newKey == stateChange.topNewState()) { activeKeys.add(newKey); } if(!isFromCompositeKey) { buildServices(states, newKey); } } } private void buildServices(StateBundle states, Key newKey) { if(!serviceTree.hasNodeWithKey(newKey)) { ServiceTree.Node node = serviceTree.createChildNode(serviceTree.getNode(newKey instanceof Child ? ((Child) newKey).parent() : rootKey), newKey); buildServicesForKey(states, newKey, node); } } private void buildServicesForKey(StateBundle states, Key newKey, ServiceTree.Node node) { newKey.bindServices(node); restoreServiceStateForKey(states, newKey, node); if(newKey instanceof Composite) { for(Object _nestedKey : ((Composite) newKey).keys()) { Key nestedKey = (Key) _nestedKey; ServiceTree.Node nestedNode = serviceTree.createChildNode(node, nestedKey); buildServicesForKey(states, (Key) _nestedKey, nestedNode); } } if(newKey.hasNestedStack()) { Backstack nestedStack = serviceTree.getNode(newKey).<BackstackManager>getService(Key.NESTED_STACK).getBackstack(); for(Object _childKey : nestedStack.getInitialParameters()) { buildServices(states, (Key) _childKey); } } } private void restoreServiceStateForKey(StateBundle states, Key key, ServiceTree.Node node) { if(states != null) { StateBundle keyBundle = states.getParcelable(key.toString()); if(keyBundle != null) { List<ServiceTree.Node.Entry> entries = node.getBoundServices(); for(ServiceTree.Node.Entry entry : entries) { if(entry.getService() instanceof Bundleable) { ((Bundleable) entry.getService()).fromBundle(keyBundle.getParcelable(entry.getName())); } } } } } public void setRestoredStates(StateBundle states) { serviceTree.getNode(rootKey).bindService(SERVICE_STATES, states); } public ServiceTree getServiceTree() { return serviceTree; } public boolean handleBack(Context context) { ServiceTree serviceTree = ServiceLocator.getService(context, ServiceLocator.SERVICE_TREE); Object lastKey = activeKeys.get(activeKeys.size() - 1); Backstack backstack = Navigator.getBackstack(context); class Cancellation { private boolean cancelled; } Cancellation cancellation = new Cancellation(); serviceTree.traverseChain(serviceTree.getNode(lastKey), (node, cancellationToken) -> { Object _key = node.getKey(); if(_key instanceof Key) { // ROOT is defined by Activity's TAG Key key = (Key) _key; if(key.hasNestedStack()) { BackstackManager backstackManager = serviceTree.getNode(key).getService(Key.NESTED_STACK); if(backstackManager.getBackstack().goBack()) { cancellation.cancelled = true; cancellationToken.cancel(); } } } }); if(cancellation.cancelled) { return true; } return backstack.goBack(); } }