/*
* Copyright (C) 2012 The Android Open Source Project
*
* 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.motorola.studio.android.model.manifest.dom;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import org.eclipse.core.runtime.IStatus;
import com.motorola.studio.android.common.IAndroidConstants;
/**
* Class that represents an <activity> node on AndroidManifest.xml file
*/
public class ActivityNode extends AbstractBuildingBlockNode
{
static
{
defaultProperties.add(PROP_ALLOWTASKREPARENTING);
defaultProperties.add(PROP_ALWAYSRETAINTASKSTATE);
defaultProperties.add(PROP_CLEARTASKONLAUNCH);
defaultProperties.add(PROP_CONFIGCHANGES);
defaultProperties.add(PROP_EXCLUDEFROMRECENTS);
defaultProperties.add(PROP_FINISHONTASKLAUNCH);
defaultProperties.add(PROP_LAUNCHMODE);
defaultProperties.add(PROP_MULTIPROCESS);
defaultProperties.add(PROP_SCREENORIENTATION);
defaultProperties.add(PROP_STATENOTNEEDED);
defaultProperties.add(PROP_TASKAFFINITY);
defaultProperties.add(PROP_THEME);
}
/**
* Enumeration for configChanges property
*/
public static enum ConfigChanges
{
mcc, mnc, locale, touchscreen, keyboard, keyboardHidden, navigation, orientation, fontscale
}
/**
* Enumeration for launchMode property
*/
public static enum LaunchMode
{
standard, singleTop, singleTask, singleInstance
}
/**
* Enumeration for screenOrientation property
*/
public static enum ScreenOrientation
{
unspecified, user, behind, landscape, portrait, sensor, nonsensor
}
/**
* Map to resolve the string<->enumeration association of configChanges property
*/
private static Map<String, ConfigChanges> configChanges;
/**
* Map to resolve the string<->enumeration association of launchMode property
*/
private static Map<String, LaunchMode> launchModes;
/**
* Map to resolve the string<->enumeration association of screenOrientation property
*/
private static Map<String, ScreenOrientation> screenOrientations;
static
{
configChanges = new HashMap<String, ConfigChanges>();
// Loads the map for configChanges
for (ConfigChanges configChange : ConfigChanges.values())
{
configChanges.put(configChange.toString().toLowerCase(), configChange);
}
launchModes = new HashMap<String, LaunchMode>();
// Loads the map for launchMode
for (LaunchMode launchMode : LaunchMode.values())
{
launchModes.put(launchMode.toString().toLowerCase(), launchMode);
}
screenOrientations = new HashMap<String, ScreenOrientation>();
// Loads the map for screenOrientation
for (ScreenOrientation screenOrientation : ScreenOrientation.values())
{
screenOrientations.put(screenOrientation.toString().toLowerCase(), screenOrientation);
}
}
/**
* Gets the configChange parameter name from a given ConfigChanges enumeration value
*
* @param configChange the enumeration value
* @return the configChange parameter name
*/
public static String getConfigChangeName(ConfigChanges configChange)
{
String name = "";
if (configChange != null)
{
name = configChange.toString();
}
return name;
}
/**
* Gets the enumeration value of the ConfigChanges enumeration from a given name
*
* @param configChangeName the configChanges name
* @return the enumeration value of the ConfigChanges enumeration
*/
public static ConfigChanges getConfigChangeFromName(String configChangeName)
{
ConfigChanges configChange = null;
if (configChangeName != null)
{
String ccn = configChangeName.trim().toLowerCase();
configChange = configChanges.get(ccn);
}
return configChange;
}
/**
* Gets the launchMode parameter name from a given LaunchMode enumeration value
*
* @param launchMode the enumeration value
* @return the LaunchMode parameter name
*/
public static String getLaunchModeName(LaunchMode launchMode)
{
String name = "";
if (launchMode != null)
{
name = launchMode.toString();
}
return name;
}
/**
* Gets the enumeration value of the LaunchMode enumeration from a given name
*
* @param launchModeName the launchMode name
* @return the enumeration value of the LaunchMode enumeration
*/
public static LaunchMode getLaunchModeFromName(String launchModeName)
{
LaunchMode launchMode = null;
if (launchModeName != null)
{
String lmn = launchModeName.trim().toLowerCase();
launchMode = launchModes.get(lmn);
}
return launchMode;
}
/**
* Gets the screenOrientation parameter name from a given ScreenOrientation enumeration value
*
* @param screenOrientation the enumeration value
* @return the ScreenOrientation parameter name
*/
public static String getScreenOrientationName(ScreenOrientation screenOrientation)
{
String name = "";
if (screenOrientation != null)
{
name = screenOrientation.toString();
}
return name;
}
/**
* Gets the enumeration value of the ScreenOrientation enumeration from a given name
*
* @param screenOrientationName the screenOrientation name
* @return the enumeration value of the ScreenOrientation enumeration
*/
public static ScreenOrientation getScreenOrientationFromName(String screenOrientationName)
{
ScreenOrientation screenOrientation = null;
if (screenOrientationName != null)
{
String son = screenOrientationName.trim().toLowerCase();
screenOrientation = screenOrientations.get(son);
}
return screenOrientation;
}
/**
* The allowTaskReparenting property
*/
private Boolean propAllowTaskReparenting = null;
/**
* The alwaysRetainTaskState property
*/
private Boolean propAlwaysRetainTaskState = null;
/**
* The clearTaskOnLaunch property
*/
private Boolean propClearTaskOnLaunch = null;
/**
* The configChanges property (can hold more than one value)
*/
private final List<ConfigChanges> propConfigChanges = new LinkedList<ConfigChanges>();
/**
* The excludeFromRecents property
*/
private Boolean propExcludeFromRecents = null;
/**
* The finishOnTaskLaunch property
*/
private Boolean propFinishOnTaskLaunch = null;
/**
* The launchMode property
*/
private LaunchMode propLaunchMode = null;
/**
* The multiProcess property
*/
private Boolean propMultiprocess = null;
/**
* The screenOrientation property
*/
private ScreenOrientation propScreenOrientation = null;
/**
* The stateNotNeeded property
*/
private Boolean propStateNotNeeded = null;
/**
* The taskAffinity property
*/
private String propTaskAffinity = null;
/**
* The theme property
*/
private String propTheme = null;
/**
* Default constructor
*
* @param name The name property. It must not be null.
*/
public ActivityNode(String name)
{
super(name);
}
/* (non-Javadoc)
* @see com.motorola.studio.android.model.manifest.dom.AndroidManifestNode#canContains(com.motorola.studio.android.model.manifest.dom.AndroidManifestNode.NodeType)
*/
@Override
protected boolean canContains(NodeType nodeType)
{
return (nodeType == NodeType.IntentFilter) || (nodeType == NodeType.MetaData)
|| (nodeType == NodeType.Comment);
}
/* (non-Javadoc)
* @see com.motorola.studio.android.model.manifest.dom.AbstractIconLabelNameNode#addAdditionalProperties()
*/
@Override
protected void addAdditionalProperties()
{
super.addAdditionalProperties();
if (propAllowTaskReparenting != null)
{
properties.put(PROP_ALLOWTASKREPARENTING, propAllowTaskReparenting.toString());
}
if (propAlwaysRetainTaskState != null)
{
properties.put(PROP_ALWAYSRETAINTASKSTATE, propAlwaysRetainTaskState.toString());
}
if (propClearTaskOnLaunch != null)
{
properties.put(PROP_CLEARTASKONLAUNCH, propClearTaskOnLaunch.toString());
}
if ((propConfigChanges != null) && !propConfigChanges.isEmpty())
{
String configChangesString = "";
for (int i = 0; i < (propConfigChanges.size() - 1); i++)
{
configChangesString += getConfigChangeName(propConfigChanges.get(i)) + "|";
}
configChangesString +=
getConfigChangeName(propConfigChanges.get(propConfigChanges.size() - 1));
properties.put(PROP_CONFIGCHANGES, configChangesString);
}
if (propExcludeFromRecents != null)
{
properties.put(PROP_EXCLUDEFROMRECENTS, propExcludeFromRecents.toString());
}
if (propFinishOnTaskLaunch != null)
{
properties.put(PROP_FINISHONTASKLAUNCH, propFinishOnTaskLaunch.toString());
}
if (propLaunchMode != null)
{
properties.put(PROP_LAUNCHMODE, getLaunchModeName(propLaunchMode));
}
if (propMultiprocess != null)
{
properties.put(PROP_MULTIPROCESS, propMultiprocess.toString());
}
if (propScreenOrientation != null)
{
properties.put(PROP_SCREENORIENTATION, getScreenOrientationName(propScreenOrientation));
}
if (propStateNotNeeded != null)
{
properties.put(PROP_STATENOTNEEDED, propStateNotNeeded.toString());
}
if (propTaskAffinity != null)
{
properties.put(PROP_TASKAFFINITY, propTaskAffinity);
}
if (propTheme != null)
{
properties.put(PROP_THEME, propTheme);
}
}
/* (non-Javadoc)
* @see com.motorola.studio.android.model.manifest.dom.AndroidManifestNode#getNodeType()
*/
@Override
public NodeType getNodeType()
{
return NodeType.Activity;
}
/* (non-Javadoc)
* @see com.motorola.studio.android.model.manifest.dom.AndroidManifestNode#isNodeValid()
*/
@Override
protected boolean isNodeValid()
{
return super.isNodeValid();
}
/**
* Gets the allowTaskReparenting property value
*
* @return the allowTaskReparenting property value
*/
public Boolean getAllowTaskReparenting()
{
return propAllowTaskReparenting;
}
/**
* Sets the allowTaskReparenting property value. Set it to null to remove it.
*
* @param allowTaskReparenting the allowTaskReparenting property value
*/
public void setAllowTaskReparenting(Boolean allowTaskReparenting)
{
this.propAllowTaskReparenting = allowTaskReparenting;
}
/**
* Gets the alwaysRetainTaskState property value
*
* @return the alwaysRetainTaskState property value
*/
public Boolean getAlwaysRetainTaskState()
{
return propAlwaysRetainTaskState;
}
/**
* Sets the alwaysRetainTaskState property value. Set it to null to remove it.
*
* @param alwaysRetainTaskState the alwaysRetainTaskState property value
*/
public void setAlwaysRetainTaskState(Boolean alwaysRetainTaskState)
{
this.propAlwaysRetainTaskState = alwaysRetainTaskState;
}
/**
* Gets the clearTaskOnLaunch property value
*
* @return the clearTaskOnLaunch property value
*/
public Boolean getClearTaskOnLaunch()
{
return propClearTaskOnLaunch;
}
/**
* Sets the clearTaskOnLaunch property value. Set it to null to remove it.
*
* @param clearTaskOnLaunch the clearTaskOnLaunch property value
*/
public void setClearTaskOnLaunch(Boolean clearTaskOnLaunch)
{
this.propClearTaskOnLaunch = clearTaskOnLaunch;
}
/**
* Gets the configChanges property value as an array
*
* @return the configChanges property value as an array
*/
public ConfigChanges[] getConfigChanges()
{
ConfigChanges[] configChanges = null;
if (propConfigChanges != null)
{
configChanges = new ConfigChanges[propConfigChanges.size()];
configChanges = propConfigChanges.toArray(configChanges);
}
return configChanges;
}
/**
* Adds a new config change to the configChanges property
*
* @param configChanges the new config change to be added
*/
public void addConfigChanges(ConfigChanges configChanges)
{
if (configChanges != null)
{
if (!propConfigChanges.contains(configChanges))
{
propConfigChanges.add(configChanges);
}
}
}
/**
* Gets the excludeFromRecents property value
*
* @return the excludeFromRecents property value
*/
public Boolean getExcludeFromRecents()
{
return propExcludeFromRecents;
}
/**
* Sets the excludeFromRecents property value. Set it to null to remove it.
*
* @param excludeFromRecents the excludeFromRecents property value
*/
public void setExcludeFromRecents(Boolean excludeFromRecents)
{
this.propExcludeFromRecents = excludeFromRecents;
}
/**
* Gets the finishOnTaskLaunch property value
*
* @return the finishOnTaskLaunch property value
*/
public Boolean getFinishOnTaskLaunch()
{
return propFinishOnTaskLaunch;
}
/**
* Sets the finishOnTaskLaunch property value. Set it to null to remove it.
*
* @param finishOnTaskLaunch the finishOnTaskLaunch property value
*/
public void setFinishOnTaskLaunch(Boolean finishOnTaskLaunch)
{
this.propFinishOnTaskLaunch = finishOnTaskLaunch;
}
/**
* Gets the launchMode property value
*
* @return the launchMode property value
*/
public LaunchMode getLaunchMode()
{
return propLaunchMode;
}
/**
* Sets the launchMode property value. Set it to null to remove it.
*
* @param launchMode the launchMode property value
*/
public void setLaunchMode(LaunchMode launchMode)
{
this.propLaunchMode = launchMode;
}
/**
* Gets the multiProcess property value
*
* @return the multiProcess property value
*/
public Boolean getMultiprocess()
{
return propMultiprocess;
}
/**
* Sets the multiProcess property value. Set it to null to remove it.
*
* @param multiProcess the multiProcess property value
*/
public void setMultiprocess(Boolean multiProcess)
{
this.propMultiprocess = multiProcess;
}
/**
* Gets the screenOrientation property value
*
* @return the screenOrientation property value
*/
public ScreenOrientation getScreenOrientation()
{
return propScreenOrientation;
}
/**
* Sets the screenOrientation property value. Set it to null to remove it.
*
* @param screenOrientation the screenOrientation property value
*/
public void setScreenOrientation(ScreenOrientation screenOrientation)
{
this.propScreenOrientation = screenOrientation;
}
/**
* Gets the stateNotNeeded property value
*
* @return the stateNotNeeded property value
*/
public Boolean getStateNotNeeded()
{
return propStateNotNeeded;
}
/**
* Sets the stateNotNeeded property value. Set it to null to remove it.
*
* @param stateNotNeeded the stateNotNeeded property value
*/
public void setStateNotNeeded(Boolean stateNotNeeded)
{
this.propStateNotNeeded = stateNotNeeded;
}
/**
* Gets the taskAffinity property value
*
* @return the taskAffinity property value
*/
public String getTaskAffinity()
{
return propTaskAffinity;
}
/**
* Sets the taskAffinity property value. Set it to null to remove it.
*
* @param taskAffinity the taskAffinity property value
*/
public void setTaskAffinity(String taskAffinity)
{
this.propTaskAffinity = taskAffinity;
}
/**
* Gets the theme property value
*
* @return the theme property value
*/
public String getTheme()
{
return propTheme;
}
/**
* Sets the theme property value. Set it to null to remove it.
*
* @param theme the theme property value
*/
public void setTheme(String theme)
{
this.propTheme = theme;
}
/**
* Adds an Intent Filter Node to the Activity Node
*
* @param intentFilter The Intent Filter Node
*/
public void addIntentFilterNode(IntentFilterNode intentFilter)
{
if (intentFilter != null)
{
if (!children.contains(intentFilter))
{
children.add(intentFilter);
}
}
}
/**
* Retrieves all Intent Filter Nodes from the Activity Node
*
* @return all Intent Filter Nodes from the Activity Node
*/
public List<IntentFilterNode> getIntentFilterNodes()
{
List<IntentFilterNode> intentFilters = new LinkedList<IntentFilterNode>();
for (AndroidManifestNode node : getAllChildrenFromType(NodeType.IntentFilter))
{
intentFilters.add((IntentFilterNode) node);
}
return intentFilters;
}
/**
* Removes an Intent Filter Node from the Activity Node
*
* @param intentFilter the Intent Filter Node to be removed
*/
public void removeIntentFilterNode(IntentFilterNode intentFilter)
{
if (intentFilter != null)
{
children.remove(intentFilter);
}
}
/**
* If parameter {@code isMainActivity} is true, then the intent-filters that represent main activities are added to this activity.
* If parameter {@code isMainActivity} is false, then the intent-filters that represent main activities are removed from this activity.
* @param isMainActivity True is this activity should be set as the main activity. False if the activity should not be set as the main activity.
* @return True if the operation requested was successfully performed. False otherwise. Possible scenarios are:
* This activity is the main activity and {@code isMainActivity} is true. In this case, this method returns true.
* This activity is the main activity and {@code isMainActivity} is false. In this case, this method returns true if the intent-filters were successfully removed from this activity node, false otherwise.
* This activity is not the main activity and {@code isMainActivity} is true. In this case, this method returns true if the required intent-filters were successfully added to this activity node, false otherwise.
* This activity is not the main activity and {@code isMainActivity} is false. In this case, this method returns true.
* */
public boolean setAsMainActivity(boolean isMainActivity)
{
boolean result = false;
// check if this this activity should be a main activity or not
if (isMainActivity)
{
// set this activity to be a main activity
if (this.isMainActivity())
{
// this already is a main activity
result = true;
}
else
{
// set as main activity
IntentFilterNode intentFilterNode = new IntentFilterNode();
ActionNode actionMainNode = new ActionNode(IAndroidConstants.ACTION_MAIN);
CategoryNode categoryLauncherNode =
new CategoryNode(IAndroidConstants.CATEGORY_LAUNCHER);
intentFilterNode.addActionNode(actionMainNode);
intentFilterNode.addCategoryNode(categoryLauncherNode);
this.addIntentFilterNode(intentFilterNode);
result = true;
}
}
else
{
// unset this activity as main activity
if (!this.isMainActivity())
{
//this activity is not a main activity
result = true;
}
else
{
// unset this activity as main activity, i.e., remove action main and category launcher from its intent-filters
for (IntentFilterNode intentFilterNode : getIntentFilterNodes())
{
ActionNode actionMainNode =
intentFilterNode.getActionNode(IAndroidConstants.ACTION_MAIN);
CategoryNode categoryLauncherNode =
intentFilterNode.getCategoryNode(IAndroidConstants.CATEGORY_LAUNCHER);
if ((actionMainNode != null) && (categoryLauncherNode != null))
{
// effectivelly remove the nodes
intentFilterNode.removeActionNode(actionMainNode);
intentFilterNode.removeCategoryNode(categoryLauncherNode);
if (intentFilterNode.isEmpty())
{
//also remove the intent-filter node if it was left empty
this.removeIntentFilterNode(intentFilterNode);
}
result = true;
}
}
}
}
return result;
}
/**
* Check if this activity is set as the main activity, i.e., if it has the required intent-filter that represent main activities.
* @return True if this activity is the main activity of the project. False otherwise.
* */
public boolean isMainActivity()
{
boolean isMainActivity = false;
boolean hasActionMain = false;
boolean hasCategoryLauncher = false;
//iterate over intent-filter nodes
//looking for action and category nodes that represents main activities
for (IntentFilterNode intent : getIntentFilterNodes())
{
hasActionMain = false;
hasCategoryLauncher = false;
//iterate over action nodes
for (ActionNode actionNode : intent.getActionNodes())
{
if (actionNode.getName().equals(IAndroidConstants.ACTION_MAIN))
{
//action node for main activities
hasActionMain = true;
break;
}
}
//iterate over category nodes
for (CategoryNode categoryNode : intent.getCategoryNodes())
{
if (categoryNode.getName().equals(IAndroidConstants.CATEGORY_LAUNCHER))
{
//category node for main activities
hasCategoryLauncher = true;
}
}
//check if the intent-filter has the action and category nodes that represent main activities
if (hasActionMain && hasCategoryLauncher)
{
isMainActivity = true;
break;
}
}
return isMainActivity;
}
/**
* Adds a Metadata Node to the Activity Node
*
* @param metadata The Metadata Node
*/
public void addMetadataNode(MetadataNode metadata)
{
if (metadata != null)
{
if (!children.contains(metadata))
{
children.add(metadata);
}
}
}
/**
* Retrieves all Metadata Nodes from the Activity Node
*
* @return all Metadata Nodes from the Activity Node
*/
public List<MetadataNode> getMetadataNodes()
{
List<MetadataNode> metadatas = new LinkedList<MetadataNode>();
for (AndroidManifestNode node : getAllChildrenFromType(NodeType.MetaData))
{
metadatas.add((MetadataNode) node);
}
return metadatas;
}
/**
* Removes a Metadata Node from the Activity Node
*
* @param metadata the Metadata Node to be removed
*/
public void removeMetadataNode(MetadataNode metadata)
{
if (metadata != null)
{
children.remove(metadata);
}
}
/* (non-Javadoc)
* @see com.motorola.studio.android.model.manifest.dom.AndroidManifestNode#getSpecificNodeErrors()
*/
@Override
protected List<IStatus> getSpecificNodeProblems()
{
return null;
}
}