| /* |
| * 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.motorolamobility.preflighting.checkers.widgetPreview; |
| |
| import java.util.ArrayList; |
| import java.util.Collections; |
| import java.util.List; |
| |
| import org.eclipse.core.runtime.IStatus; |
| import org.w3c.dom.DOMException; |
| import org.w3c.dom.Document; |
| import org.w3c.dom.NamedNodeMap; |
| import org.w3c.dom.Node; |
| import org.w3c.dom.NodeList; |
| |
| import com.motorolamobility.preflighting.checkers.CheckerPlugin; |
| import com.motorolamobility.preflighting.checkers.i18n.CheckerNLS; |
| import com.motorolamobility.preflighting.core.applicationdata.ApplicationData; |
| import com.motorolamobility.preflighting.core.applicationdata.Element; |
| import com.motorolamobility.preflighting.core.applicationdata.Element.Type; |
| import com.motorolamobility.preflighting.core.applicationdata.ElementUtils; |
| import com.motorolamobility.preflighting.core.applicationdata.FolderElement; |
| import com.motorolamobility.preflighting.core.applicationdata.ResourcesFolderElement; |
| import com.motorolamobility.preflighting.core.applicationdata.XMLElement; |
| import com.motorolamobility.preflighting.core.checker.condition.CanExecuteConditionStatus; |
| import com.motorolamobility.preflighting.core.checker.condition.Condition; |
| import com.motorolamobility.preflighting.core.checker.condition.ICondition; |
| import com.motorolamobility.preflighting.core.devicespecification.DeviceSpecification; |
| import com.motorolamobility.preflighting.core.exception.PreflightingCheckerException; |
| import com.motorolamobility.preflighting.core.internal.cond.utils.ConditionUtils; |
| import com.motorolamobility.preflighting.core.utils.CheckerUtils; |
| import com.motorolamobility.preflighting.core.validation.ValidationManagerConfiguration; |
| import com.motorolamobility.preflighting.core.validation.ValidationResult; |
| import com.motorolamobility.preflighting.core.validation.ValidationResultData; |
| |
| public class MissingWidgetPreviewTagCondition extends Condition implements ICondition |
| { |
| |
| /** |
| * |
| */ |
| private static final int MIN_TABLET_SDK_VERSION = 11; |
| |
| @Override |
| public void execute(ApplicationData data, List<DeviceSpecification> deviceSpecs, |
| ValidationManagerConfiguration valManagerConfig, ValidationResult results) |
| throws PreflightingCheckerException |
| { |
| ArrayList<ValidationResultData> resultDataList = new ArrayList<ValidationResultData>(); |
| |
| boolean hasTag = true; |
| |
| FolderElement xmlFolder = null; |
| XMLElement xmlFileElement = data.getManifestElement(); |
| |
| //Getting the sdk version, because only from android 3.0 on the previewImage is supported |
| String minSdkStr = CheckerUtils.getMinSdk(xmlFileElement.getDocument()); |
| int minSdkVersion = -1; |
| try |
| { |
| minSdkVersion = Integer.parseInt(minSdkStr); |
| } |
| catch (NumberFormatException e) |
| { |
| minSdkVersion = -1; |
| } |
| |
| //it only makes sense to check for previewImage in widgets applications |
| boolean isWidget = isWidgetAplication(data); |
| |
| //is a widget and is for android 3.0 and above version |
| if ((minSdkVersion >= MIN_TABLET_SDK_VERSION) && (isWidget)) |
| { |
| |
| xmlFolder = getXMLFolder(data); |
| //Get the xml filename responsible for the widget resources |
| ArrayList<String> xmlFilename = getWidgetResourceFilename(data); |
| |
| for (String resourceFile : xmlFilename) |
| { |
| ValidationResultData resultData = new ValidationResultData(); |
| //get the actual xml file element |
| xmlFileElement = getXMLFile(xmlFolder, resourceFile); |
| |
| //check for the android:previewImage tag |
| hasTag = checkForPreviewTag(xmlFileElement); |
| |
| if (hasTag) |
| { |
| //it is not a widget OR is not android 3.0+ version OR everything went fine |
| resultData.setSeverity(ValidationResultData.SEVERITY.OK); |
| |
| } |
| else |
| { |
| //start build the result |
| resultData.setSeverity(getSeverityLevel()); |
| resultData.setConditionID(getId()); |
| resultData.setInfoURL(ConditionUtils.getDescriptionLink(getChecker().getId(), |
| getId(), valManagerConfig)); |
| resultData |
| .setQuickFixSuggestion(CheckerNLS.MissingWidgetPreviewTagCondition_quickFix); |
| resultData |
| .setIssueDescription(CheckerNLS.MissingWidgetPreviewTagCondition_WarningMessage); |
| |
| resultData.addFileToIssueLines(xmlFileElement.getFile(), |
| Collections.<Integer> emptyList()); |
| |
| } |
| resultDataList.add(resultData); |
| |
| } |
| } |
| results.addAll(resultDataList); |
| |
| } |
| |
| @Override |
| public CanExecuteConditionStatus canExecute(ApplicationData data, |
| List<DeviceSpecification> deviceSpecs) throws PreflightingCheckerException |
| { |
| CanExecuteConditionStatus status = |
| new CanExecuteConditionStatus(IStatus.OK, CheckerPlugin.PLUGIN_ID, null); |
| status.setConditionId(getId()); |
| |
| XMLElement manElem = data.getManifestElement(); |
| if (manElem == null) |
| { |
| status = |
| new CanExecuteConditionStatus(IStatus.ERROR, CheckerPlugin.PLUGIN_ID, |
| CheckerNLS.Invalid_ManifestFile); |
| status.setConditionId(getId()); |
| } |
| else |
| { |
| Document manifestDoc = manElem.getDocument(); |
| |
| if (manifestDoc == null) |
| { |
| status = |
| new CanExecuteConditionStatus(IStatus.ERROR, CheckerPlugin.PLUGIN_ID, |
| CheckerNLS.Invalid_ManifestFile); |
| status.setConditionId(getId()); |
| } |
| } |
| |
| return status; |
| } |
| |
| /** |
| * This Method check for the widget related intent in order to determine if the application |
| * is a widget |
| * |
| * @param data |
| * @return whether the application is a widget project or not |
| * @throws PreflightingCheckerException |
| */ |
| |
| private boolean isWidgetAplication(ApplicationData data) throws PreflightingCheckerException |
| { |
| Boolean actionFound = false; |
| XMLElement manElem = data.getManifestElement(); |
| if (manElem != null) |
| { |
| Document manifestDoc = manElem.getDocument(); |
| if (manifestDoc != null) |
| { |
| NodeList rcvLst = manifestDoc.getElementsByTagName("receiver"); //$NON-NLS-1$ |
| |
| for (int receiverIndex = 0; receiverIndex < rcvLst.getLength(); receiverIndex++) |
| { |
| |
| NodeList intentFilterLst = rcvLst.item(receiverIndex).getChildNodes(); |
| for (int intentFilterIndex = 0; intentFilterIndex < intentFilterLst.getLength(); intentFilterIndex++) |
| { |
| Node intentFilterNode = intentFilterLst.item(intentFilterIndex); |
| // get intent-filter nodes |
| if (intentFilterNode.getNodeName().equals("intent-filter")) //$NON-NLS-1$ |
| { |
| NodeList actionLst = intentFilterNode.getChildNodes(); |
| for (int actionListIndex = 0; actionListIndex < actionLst.getLength(); actionListIndex++) |
| { |
| Node actionNode = actionLst.item(actionListIndex); |
| // get action nodes |
| if (actionNode.getNodeName().equals("action")) //$NON-NLS-1$ |
| { |
| NamedNodeMap map = actionNode.getAttributes(); |
| // name attribute must be set to |
| // android.appwidget.action.APPWIDGET_UPDATE |
| Node nameAtr = map.getNamedItem("android:name"); //$NON-NLS-1$ |
| |
| try |
| { |
| if ((nameAtr != null) |
| && nameAtr |
| .getNodeValue() |
| .equals("android.appwidget.action.APPWIDGET_UPDATE")) //$NON-NLS-1$ |
| { |
| actionFound = true; |
| |
| } |
| |
| } |
| catch (DOMException e) |
| { |
| // Error retrieving value of the action intent |
| throw new PreflightingCheckerException( |
| CheckerNLS.MainActivityChecker_Exception_Get_Action_Intent_Value, |
| e); |
| } |
| } |
| |
| } |
| |
| } |
| |
| } |
| } |
| } |
| } |
| return actionFound; |
| } |
| |
| /** |
| * This method retrieves the filename of the widget resouces XML pointed in the AndroidManifest |
| * @param data |
| * @return the filename |
| */ |
| |
| private ArrayList<String> getWidgetResourceFilename(ApplicationData data) |
| { |
| |
| ArrayList<String> xmlFilename = new ArrayList<String>(); |
| |
| XMLElement manElem = data.getManifestElement(); |
| if (manElem != null) |
| { |
| Document manifestDoc = manElem.getDocument(); |
| if (manifestDoc != null) |
| { |
| NodeList actLst = manifestDoc.getElementsByTagName("receiver"); //$NON-NLS-1$ |
| |
| for (int k = 0; k < actLst.getLength(); k++) |
| { |
| |
| NodeList intentFilterLst = actLst.item(k).getChildNodes(); |
| for (int j = 0; j < intentFilterLst.getLength(); j++) |
| { |
| Node metaDataNode = intentFilterLst.item(j); |
| // get meta-data |
| if (metaDataNode.getNodeName().equals("meta-data")) //$NON-NLS-1$ |
| { |
| |
| NamedNodeMap map = metaDataNode.getAttributes(); |
| // name attribute must be set to |
| // android.appwidget.provider |
| Node nameAtr = map.getNamedItem("android:name"); //$NON-NLS-1$ |
| |
| try |
| { |
| if ((nameAtr != null) |
| && nameAtr.getNodeValue().equals( |
| "android.appwidget.provider")) //$NON-NLS-1$ |
| { |
| Node resourceAtr = map.getNamedItem("android:resource"); //$NON-NLS-1$ |
| if (resourceAtr != null) |
| { |
| |
| xmlFilename.add(resourceAtr.getNodeValue() |
| .substring( |
| xmlFilename.indexOf("@xml/") |
| + "@xml/".length() + 1)); |
| |
| } |
| |
| } |
| |
| } |
| catch (DOMException e) |
| { |
| // DO Nothing |
| } |
| } |
| |
| } |
| |
| } |
| |
| } |
| } |
| return xmlFilename; //$NON-NLS-1$ //$NON-NLS-2$ |
| } |
| |
| /** |
| * This method gets the xml folder of the project |
| * |
| * @param data |
| * @return the xml folder |
| */ |
| |
| private FolderElement getXMLFolder(ApplicationData data) |
| { |
| List<Element> folderResElements = |
| ElementUtils.getElementByType(data.getRootElement(), Type.FOLDER_RES); |
| FolderElement xmlFolder = null; |
| ResourcesFolderElement resFolder = |
| folderResElements.size() > 0 ? (ResourcesFolderElement) folderResElements.get(0) |
| : null; |
| |
| if (resFolder != null) |
| { |
| for (Element element : resFolder.getChildren()) |
| { |
| if ((element instanceof FolderElement) && (element.getName().equals("xml"))) //$NON-NLS-1$ |
| { |
| xmlFolder = (FolderElement) element; |
| } |
| } |
| } |
| return xmlFolder; |
| } |
| |
| private XMLElement getXMLFile(FolderElement xmlFolder, String xmlFilename) |
| { |
| XMLElement xmlFileElement = null; |
| if (xmlFolder instanceof FolderElement) |
| { |
| for (Element element : xmlFolder.getChildren()) |
| { |
| if (element.getName().equals(xmlFilename + ".xml") //$NON-NLS-1$ |
| && (element instanceof XMLElement)) |
| { |
| xmlFileElement = (XMLElement) element; |
| } |
| |
| } |
| } |
| return xmlFileElement; |
| } |
| |
| /** |
| * @param xmlFileElement |
| * @return |
| */ |
| private boolean checkForPreviewTag(XMLElement xmlFileElement) |
| { |
| boolean hasPreviewImage = false; |
| if (xmlFileElement != null) |
| { |
| Document resourceDoc = xmlFileElement.getDocument(); |
| if (resourceDoc != null) |
| { |
| NodeList provLst = resourceDoc.getElementsByTagName("appwidget-provider"); //$NON-NLS-1$ |
| |
| for (int k = 0; k < provLst.getLength(); k++) |
| { |
| |
| NamedNodeMap atrMap = provLst.item(k).getAttributes(); |
| Node previewImageNode = atrMap.getNamedItem("android:previewImage"); //$NON-NLS-1$ |
| |
| if (previewImageNode != null) |
| { |
| hasPreviewImage = true; |
| } |
| } |
| } |
| } |
| return hasPreviewImage; |
| |
| } |
| |
| } |