// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

package org.chromium.content.browser;

import android.content.Context;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
import android.os.Bundle;
import android.util.Log;

import java.util.List;

/**
 * {@link PepperPluginManager} collects meta data about plugins from preloaded android apps
 * that reply to PEPPERPLUGIN intent query.
 */
public class PepperPluginManager {

    private static final String LOGTAG = "PepperPluginManager";

    /**
     * Service Action: A plugin wishes to be loaded in the ContentView must
     * provide {@link android.content.IntentFilter IntentFilter} that accepts
     * this action in its AndroidManifest.xml.
     */
    public static final String PEPPER_PLUGIN_ACTION = "org.chromium.intent.PEPPERPLUGIN";
    public static final String PEPPER_PLUGIN_ROOT = "/system/lib/pepperplugin/";

    // A plugin will specify the following fields in its AndroidManifest.xml.
    private static final String FILENAME = "filename";
    private static final String MIMETYPE = "mimetype";
    private static final String NAME = "name";
    private static final String DESCRIPTION = "description";
    private static final String VERSION = "version";

    private static String getPluginDescription(Bundle metaData) {
        // Find the name of the plugin's shared library.
        String filename = metaData.getString(FILENAME);
        if (filename == null || filename.isEmpty()) {
            return null;
        }
        // Find the mimetype of the plugin. Flash is handled in getFlashPath.
        String mimetype = metaData.getString(MIMETYPE);
        if (mimetype == null || mimetype.isEmpty()) {
            return null;
        }
        // Assemble the plugin info, according to the format described in
        // pepper_plugin_list.cc.
        // (eg. path<#name><#description><#version>;mimetype)
        StringBuffer plugin = new StringBuffer(PEPPER_PLUGIN_ROOT);
        plugin.append(filename);

        // Find the (optional) name/description/version of the plugin.
        String name = metaData.getString(NAME);
        String description = metaData.getString(DESCRIPTION);
        String version = metaData.getString(VERSION);

        if (name != null && !name.isEmpty()) {
            plugin.append("#");
            plugin.append(name);
            if (description != null && !description.isEmpty()) {
                plugin.append("#");
                plugin.append(description);
                if (version != null && !version.isEmpty()) {
                    plugin.append("#");
                    plugin.append(version);
                }
            }
        }
        plugin.append(';');
        plugin.append(mimetype);

        return plugin.toString();
    }

    /**
     * Collects information about installed plugins and returns a plugin description
     * string, which will be appended to for command line to load plugins.
     *
     * @param context Android context
     * @return        Description string for plugins
     */
    public static String getPlugins(final Context context) {
        StringBuffer ret = new StringBuffer();
        PackageManager pm = context.getPackageManager();
        List<ResolveInfo> plugins = pm.queryIntentServices(
                new Intent(PEPPER_PLUGIN_ACTION),
                PackageManager.GET_SERVICES | PackageManager.GET_META_DATA);
        for (ResolveInfo info : plugins) {
            // Retrieve the plugin's service information.
            ServiceInfo serviceInfo = info.serviceInfo;
            if (serviceInfo == null || serviceInfo.metaData == null ||
                    serviceInfo.packageName == null) {
                Log.e(LOGTAG, "Can't get service information from " + info);
                continue;
            }

            // Retrieve the plugin's package information.
            PackageInfo pkgInfo;
            try {
                pkgInfo = pm.getPackageInfo(serviceInfo.packageName, 0);
            } catch (NameNotFoundException e) {
                Log.e(LOGTAG, "Can't find plugin: " + serviceInfo.packageName);
                continue;
            }
            if (pkgInfo == null ||
                    (pkgInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0) {
                continue;
            }
            Log.i(LOGTAG, "The given plugin package is preloaded: " + serviceInfo.packageName);

            String plugin = getPluginDescription(serviceInfo.metaData);
            if (plugin == null) {
                continue;
            }
            if (ret.length() > 0) {
                ret.append(',');
            }
            ret.append(plugin);
        }
        return ret.toString();
    }
}
