content: /*
   * Copyright 2018 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.android.server.pm;
  
  import android.annotation.NonNull;
  import android.text.TextUtils;
  
  import org.xmlpull.v1.XmlPullParser;
  import org.xmlpull.v1.XmlPullParserException;
  import org.xmlpull.v1.XmlSerializer;
  
  import java.io.IOException;
  import java.util.ArrayList;
  
  /**
   * Represents a Share Target definition, read from the application's manifest (shortcuts.xml)
   */
  class ShareTargetInfo {
  
      private static final String TAG_SHARE_TARGET = "share-target";
      private static final String ATTR_TARGET_CLASS = "targetClass";
  
      private static final String TAG_DATA = "data";
      private static final String ATTR_SCHEME = "scheme";
      private static final String ATTR_HOST = "host";
      private static final String ATTR_PORT = "port";
      private static final String ATTR_PATH = "path";
      private static final String ATTR_PATH_PATTERN = "pathPattern";
      private static final String ATTR_PATH_PREFIX = "pathPrefix";
      private static final String ATTR_MIME_TYPE = "mimeType";
  
      private static final String TAG_CATEGORY = "category";
      private static final String ATTR_NAME = "name";
  
      static class TargetData {
          final String mScheme;
          final String mHost;
          final String mPort;
          final String mPath;
          final String mPathPattern;
          final String mPathPrefix;
          final String mMimeType;
  
          TargetData(String scheme, String host, String port, String path, String pathPattern,
                  String pathPrefix, String mimeType) {
              mScheme = scheme;
              mHost = host;
              mPort = port;
              mPath = path;
              mPathPattern = pathPattern;
              mPathPrefix = pathPrefix;
              mMimeType = mimeType;
          }
  
          public void toStringInner(StringBuilder strBuilder) {
              if (!TextUtils.isEmpty(mScheme)) {
                  strBuilder.append(" scheme=").append(mScheme);
              }
              if (!TextUtils.isEmpty(mHost)) {
                  strBuilder.append(" host=").append(mHost);
              }
              if (!TextUtils.isEmpty(mPort)) {
                  strBuilder.append(" port=").append(mPort);
              }
              if (!TextUtils.isEmpty(mPath)) {
                  strBuilder.append(" path=").append(mPath);
              }
              if (!TextUtils.isEmpty(mPathPattern)) {
                  strBuilder.append(" pathPattern=").append(mPathPattern);
              }
              if (!TextUtils.isEmpty(mPathPrefix)) {
                  strBuilder.append(" pathPrefix=").append(mPathPrefix);
              }
              if (!TextUtils.isEmpty(mMimeType)) {
                  strBuilder.append(" mimeType=").append(mMimeType);
              }
          }
  
          @Override
          public String toString() {
              StringBuilder strBuilder = new StringBuilder();
              toStringInner(strBuilder);
              return strBuilder.toString();
          }
      }
  
      final TargetData[] mTargetData;
      final String mTargetClass;
      final String[] mCategories;
  
      ShareTargetInfo(TargetData[] data, String targetClass, String[] categories) {
          mTargetData = data;
          mTargetClass = targetClass;
          mCategories = categories;
      }
  
      @Override
      public String toString() {
          StringBuilder strBuilder = new StringBuilder();
          strBuilder.append("targetClass=").append(mTargetClass);
          for (int i = 0; i < mTargetData.length; i++) {
              strBuilder.append(" data={");
              mTargetData[i].toStringInner(strBuilder);
              strBuilder.append("}");
          }
          for (int i = 0; i < mCategories.length; i++) {
              strBuilder.append(" category=").append(mCategories[i]);
          }
  
          return strBuilder.toString();
      }
  
      void saveToXml(@NonNull XmlSerializer out) throws IOException {
          out.startTag(null, TAG_SHARE_TARGET);
  
          ShortcutService.writeAttr(out, ATTR_TARGET_CLASS, mTargetClass);
  
          for (int i = 0; i < mTargetData.length; i++) {
              out.startTag(null, TAG_DATA);
              ShortcutService.writeAttr(out, ATTR_SCHEME, mTargetData[i].mScheme);
              ShortcutService.writeAttr(out, ATTR_HOST, mTargetData[i].mHost);
              ShortcutService.writeAttr(out, ATTR_PORT, mTargetData[i].mPort);
              ShortcutService.writeAttr(out, ATTR_PATH, mTargetData[i].mPath);
              ShortcutService.writeAttr(out, ATTR_PATH_PATTERN, mTargetData[i].mPathPattern);
              ShortcutService.writeAttr(out, ATTR_PATH_PREFIX, mTargetData[i].mPathPrefix);
              ShortcutService.writeAttr(out, ATTR_MIME_TYPE, mTargetData[i].mMimeType);
              out.endTag(null, TAG_DATA);
          }
  
          for (int i = 0; i < mCategories.length; i++) {
              out.startTag(null, TAG_CATEGORY);
              ShortcutService.writeAttr(out, ATTR_NAME, mCategories[i]);
              out.endTag(null, TAG_CATEGORY);
          }
  
          out.endTag(null, TAG_SHARE_TARGET);
      }
  
      static ShareTargetInfo loadFromXml(XmlPullParser parser)
              throws IOException, XmlPullParserException {
          final String targetClass = ShortcutService.parseStringAttribute(parser, ATTR_TARGET_CLASS);
          final ArrayList<ShareTargetInfo.TargetData> targetData = new ArrayList<>();
          final ArrayList<String> categories = new ArrayList<>();
  
          int type;
          while ((type = parser.next()) != XmlPullParser.END_DOCUMENT) {
              if (type == XmlPullParser.START_TAG) {
                  switch (parser.getName()) {
                      case TAG_DATA:
                          targetData.add(parseTargetData(parser));
                          break;
                      case TAG_CATEGORY:
                          categories.add(ShortcutService.parseStringAttribute(parser, ATTR_NAME));
                          break;
                  }
              } else if (type == XmlPullParser.END_TAG && parser.getName().equals(TAG_SHARE_TARGET)) {
                  break;
              }
          }
          if (targetData.isEmpty() || targetClass == null || categories.isEmpty()) {
              return null;
          }
          return new ShareTargetInfo(
                  targetData.toArray(new ShareTargetInfo.TargetData[targetData.size()]),
                  targetClass, categories.toArray(new String[categories.size()]));
      }
  
      private static ShareTargetInfo.TargetData parseTargetData(XmlPullParser parser) {
          final String scheme = ShortcutService.parseStringAttribute(parser, ATTR_SCHEME);
          final String host = ShortcutService.parseStringAttribute(parser, ATTR_HOST);
          final String port = ShortcutService.parseStringAttribute(parser, ATTR_PORT);
          final String path = ShortcutService.parseStringAttribute(parser, ATTR_PATH);
          final String pathPattern = ShortcutService.parseStringAttribute(parser, ATTR_PATH_PATTERN);
          final String pathPrefix = ShortcutService.parseStringAttribute(parser, ATTR_PATH_PREFIX);
          final String mimeType = ShortcutService.parseStringAttribute(parser, ATTR_MIME_TYPE);
  
          return new ShareTargetInfo.TargetData(scheme, host, port, path, pathPattern, pathPrefix,
                  mimeType);
      }
  }
  