Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit d0abcede authored by Fabrice Di Meglio's avatar Fabrice Di Meglio Committed by Android (Google) Code Review
Browse files

Merge "Introduce the SearchIndexablesProvider and its friends"

parents 024a003d b49995d4
Loading
Loading
Loading
Loading
+117 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2014 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 android.provider;

import android.content.Context;

import java.util.Locale;

/**
 * The Indexable data for Search. This abstract class defines the common parts for all search
 * indexable data.
 *
 * @hide
 */
public abstract class SearchIndexableData {

    /**
     * The context for the data. Will usually allow to retrieve some resources.
     *
     * @see Context
     */
    public Context context;

    /**
     * The locale for the data
     */
    public Locale locale;

    /**
     * The rank for the data. This is application specific.
     */
    public int rank;

    /**
     * The class name associated with the data. Generally this is a Fragment class name for
     * referring where the data is coming from and for launching the associated Fragment for
     * displaying the data. This is used only when the data is provided "locally".
     *
     * If the data is provided "externally", the relevant information come from the
     * {@link SearchIndexableData#intentAction} and {@link SearchIndexableData#intentTargetPackage}
     * and {@link SearchIndexableData#intentTargetClass}.
     *
     * @see SearchIndexableData#intentAction
     * @see SearchIndexableData#intentTargetPackage
     * @see SearchIndexableData#intentTargetClass
     */
    public String className;

    /**
     * The package name for retrieving the icon associated with the data.
     *
     * @see SearchIndexableData#iconResId
     */
    public String packageName;

    /**
     * The icon resource ID associated with the data.
     *
     * @see SearchIndexableData#packageName
     */
    public int iconResId;

    /**
     * The Intent action associated with the data. This is used when the
     * {@link SearchIndexableData#className} is not relevant.
     *
     * @see SearchIndexableData#intentTargetPackage
     * @see SearchIndexableData#intentTargetClass
     */
    public String intentAction;

    /**
     * The Intent target package associated with the data.
     *
     * @see SearchIndexableData#intentAction
     * @see SearchIndexableData#intentTargetClass
     */
    public String intentTargetPackage;

    /**
     * The Intent target class associated with the data.
     *
     * @see SearchIndexableData#intentAction
     * @see SearchIndexableData#intentTargetPackage
     */
    public String intentTargetClass;

    /**
     * Default constructor.
     */
    public SearchIndexableData() {
    }

    /**
     * Constructor with a {@link Context}.
     *
     * @param ctx the Context
     */
    public SearchIndexableData(Context ctx) {
        context = ctx;
        locale = Locale.getDefault();
    }
}
+65 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2014 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 android.provider;

import android.content.Context;

/**
 * Search Indexable Resource.
 *
 * This class wraps a set of reference information representing data that can be indexed from a
 * resource which would typically be a {@link android.preference.PreferenceScreen}.
 *
 * xmlResId: the resource ID of a {@link android.preference.PreferenceScreen} XML file.
 *
 * @see SearchIndexableData
 * @see android.preference.PreferenceScreen
 *
 * @hide
 */
public class SearchIndexableResource extends SearchIndexableData {

    /**
     * Resource ID of the associated {@link android.preference.PreferenceScreen} XML file.
     */
    public int xmlResId;

    /**
     * Constructor.
     *
     * @param rank the rank of the data.
     * @param xmlResId the resource ID of a {@link android.preference.PreferenceScreen} XML file.
     * @param className the class name associated with the data (generally a
     *                  {@link android.app.Fragment}).
     * @param iconResId the resource ID associated with the data.
     */
    public SearchIndexableResource(int rank, int xmlResId, String className, int iconResId) {
        this.rank = rank;
        this.xmlResId = xmlResId;
        this.className = className;
        this.iconResId = iconResId;
    }

    /**
     * Constructor.
     *
     * @param context the Context associated with the data.
     */
    public SearchIndexableResource(Context context) {
        super(context);
    }
}
 No newline at end of file
+179 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2014 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 android.provider;

import android.content.ContentResolver;

/**
 * Describe the contract for an Indexable data.
 *
 * @hide
 */
public class SearchIndexablesContract {

    /**
     * Intent action used to identify {@link SearchIndexablesProvider}
     * instances. This is used in the {@code <intent-filter>} of a {@code <provider>}.
     */
    public static final String PROVIDER_INTERFACE =
            "android.content.action.SEARCH_INDEXABLES_PROVIDER";

    private static final String SETTINGS = "settings";

    /**
     * Indexable references name.
     */
    public static final String INDEXABLES_XML_RES = "indexables_xml_res";

    /**
     * ContentProvider path for indexable xml resources.
     */
    public static final String INDEXABLES_XML_RES_PATH = SETTINGS + "/" + INDEXABLES_XML_RES;

    /**
     * Indexable raw data name.
     */
    public static final String INDEXABLES_RAW = "indexables_raw";

    /**
     * ContentProvider path for indexable raw data.
     */
    public static final String INDEXABLES_RAW_PATH = SETTINGS + "/" + INDEXABLES_RAW;

    /**
     * Indexable xml resources colums.
     */
    public static final String[] INDEXABLES_XML_RES_COLUMNS = new String[] {
            XmlResource.COLUMN_RANK,
            XmlResource.COLUMN_XML_RESID,
            XmlResource.COLUMN_CLASS_NAME,
            XmlResource.COLUMN_ICON_RESID,
            XmlResource.COLUMN_INTENT_ACTION,
            XmlResource.COLUMN_INTENT_TARGET_PACKAGE,
            XmlResource.COLUMN_INTENT_TARGET_CLASS
    };

    /**
     * Indexable raw data colums.
     */
    public static final String[] INDEXABLES_RAW_COLUMNS = new String[] {
            RawData.COLUMN_RANK,
            RawData.COLUMN_TITLE,
            RawData.COLUMN_SUMMARY,
            RawData.COLUMN_KEYWORDS,
            RawData.COLUMN_SCREEN_TITLE,
            RawData.COLUMN_CLASS_NAME,
            RawData.COLUMN_ICON_RESID,
            RawData.COLUMN_INTENT_ACTION,
            RawData.COLUMN_INTENT_TARGET_PACKAGE,
            RawData.COLUMN_INTENT_TARGET_CLASS,
    };

    /**
     * Constants related to a {@link SearchIndexableResource}.
     *
     * This is a description of
     */
    public static final class XmlResource extends BaseColumns {
        private XmlResource() {
        }

        public static final String MIME_TYPE = ContentResolver.CURSOR_DIR_BASE_TYPE +
                "/" + INDEXABLES_XML_RES;

        /**
         * XML resource ID for the {@link android.preference.PreferenceScreen} to load and index.
         */
        public static final String COLUMN_XML_RESID = "xmlResId";
    }

    /**
     * Constants related to a {@link SearchIndexableData}.
     *
     * This is the raw data that is stored into an Index. This is related to
     * {@link android.preference.Preference} and its attributes like
     * {@link android.preference.Preference#getTitle()},
     * {@link android.preference.Preference#getSummary()}, etc.
     *
     */
    public static final class RawData extends BaseColumns {
        private RawData() {
        }

        public static final String MIME_TYPE = ContentResolver.CURSOR_DIR_BASE_TYPE +
                "/" + INDEXABLES_RAW;

        /**
         * Title's raw data.
         */
        public static final String COLUMN_TITLE = "title";

        /**
         * Summary's raw data.
         */
        public static final String COLUMN_SUMMARY = "summary";

        /**
         * Keywords' raw data.
         */
        public static final String COLUMN_KEYWORDS = "keywords";

        /**
         * Fragment's title associated with the raw data.
         */
        public static final String COLUMN_SCREEN_TITLE = "screenTitle";
    }

    /**
     * The base columns.
     */
    private static class BaseColumns {
        private BaseColumns() {
        }

        /**
         * Rank of the data. This is an integer used for ranking the search results. This is
         * application specific.
         */
        public static final String COLUMN_RANK = "rank";

        /**
         * Class name associated with the data (usually a Fragment class name).
         */
        public static final String COLUMN_CLASS_NAME = "className";

        /**
         * Icon resource ID for the data.
         */
        public static final String COLUMN_ICON_RESID = "iconResId";

        /**
         * Intent action associated with the data.
         */
        public static final String COLUMN_INTENT_ACTION = "intentAction";

        /**
         * Intent target package associated with the data.
         */
        public static final String COLUMN_INTENT_TARGET_PACKAGE = "intentTargetPackage";

        /**
         * Intent target class associated with the data.
         */
        public static final String COLUMN_INTENT_TARGET_CLASS = "intentTargetClass";
    }
}
+174 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2014 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 android.provider;

import android.content.ContentProvider;
import android.content.ContentValues;
import android.content.Context;
import android.content.UriMatcher;
import android.content.pm.ProviderInfo;
import android.database.Cursor;
import android.net.Uri;

/**
 * Base class for a search indexable provider. Such provider offers data to be indexed either
 * as a reference to an XML file (like a {@link android.preference.PreferenceScreen}) or either
 * as some raw data.
 *
 * @see SearchIndexableResource
 * @see SearchIndexableData
 * @see SearchIndexablesContract
 *
 * To create a search indexables provider, extend this class, then implement the abstract methods,
 * and add it to your manifest like this:
 *
 * <pre class="prettyprint">&lt;manifest&gt;
 *    ...
 *    &lt;application&gt;
 *        ...
 *        &lt;provider
 *            android:name="com.example.MyIndexablesProvider"
 *            android:authorities="com.example.myindexablesprovider"
 *            android:exported="true"
 *            android:grantUriPermissions="true"
 *            android:permission="android.permission.READ_SEARCH_INDEXABLES"
 *            &lt;intent-filter&gt;
 *                &lt;action android:name="android.content.action.SEARCH_INDEXABLES_PROVIDER" /&gt;
 *            &lt;/intent-filter&gt;
 *        &lt;/provider&gt;
 *        ...
 *    &lt;/application&gt;
 *&lt;/manifest&gt;</pre>
 * <p>
 * When defining your provider, you must protect it with
 * {@link android.Manifest.permission#READ_SEARCH_INDEXABLES}, which is a permission only the system
 * can obtain.
 * </p>
 *
 * @hide
 */
public abstract class SearchIndexablesProvider extends ContentProvider {
    private static final String TAG = "IndexablesProvider";

    private String mAuthority;
    private UriMatcher mMatcher;

    private static final int MATCH_RES_CODE = 1;
    private static final int MATCH_RAW_CODE = 2;

    /**
     * Implementation is provided by the parent class.
     */
    @Override
    public void attachInfo(Context context, ProviderInfo info) {
        mAuthority = info.authority;

        mMatcher = new UriMatcher(UriMatcher.NO_MATCH);
        mMatcher.addURI(mAuthority, SearchIndexablesContract.INDEXABLES_XML_RES_PATH,
                MATCH_RES_CODE);
        mMatcher.addURI(mAuthority, SearchIndexablesContract.INDEXABLES_RAW_PATH,
                MATCH_RAW_CODE);

        // Sanity check our setup
        if (!info.exported) {
            throw new SecurityException("Provider must be exported");
        }
        if (!info.grantUriPermissions) {
            throw new SecurityException("Provider must grantUriPermissions");
        }
        if (!android.Manifest.permission.READ_SEARCH_INDEXABLES.equals(info.readPermission)) {
            throw new SecurityException("Provider must be protected by READ_SEARCH_INDEXABLES");
        }

        super.attachInfo(context, info);
    }

    @Override
    public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
                        String sortOrder) {
        switch (mMatcher.match(uri)) {
            case MATCH_RES_CODE:
                return queryXmlResources(null);
            case MATCH_RAW_CODE:
                return queryRawData(null);
            default:
                throw new UnsupportedOperationException("Unknown Uri " + uri);
        }
    }

    /**
     * Returns all {@link android.provider.SearchIndexablesContract.XmlResource}.
     *
     * Those are usually xml resource ID to some {@link android.preference.PreferenceScreen}.
     *
     * @param projection list of {@link android.provider.SearchIndexablesContract.XmlResource}
     *                   columns to put into the cursor. If {@code null} all supported columns
     *                   should be included.
     */
    public abstract Cursor queryXmlResources(String[] projection);

    /**
     * Returns all {@link android.provider.SearchIndexablesContract.RawData}.
     *
     * Those are raw indexable data.
     *
     * @param projection list of {@link android.provider.SearchIndexablesContract.RawData} columns
     *                   to put into the cursor. If {@code null} all supported columns should be
     *                   included.
     */
    public abstract Cursor queryRawData(String[] projection);

    @Override
    public String getType(Uri uri) {
        switch (mMatcher.match(uri)) {
            case MATCH_RES_CODE:
                return SearchIndexablesContract.XmlResource.MIME_TYPE;
            case MATCH_RAW_CODE:
                return SearchIndexablesContract.RawData.MIME_TYPE;
            default:
                throw new IllegalArgumentException("Unknown URI " + uri);
        }
    }

    /**
     * Implementation is provided by the parent class. Throws by default, and
     * cannot be overriden.
     */
    @Override
    public final Uri insert(Uri uri, ContentValues values) {
        throw new UnsupportedOperationException("Insert not supported");
    }

    /**
     * Implementation is provided by the parent class. Throws by default, and
     * cannot be overriden.
     */
    @Override
    public final int delete(Uri uri, String selection, String[] selectionArgs) {
        throw new UnsupportedOperationException("Delete not supported");
    }

    /**
     * Implementation is provided by the parent class. Throws by default, and
     * cannot be overriden.
     */
    @Override
    public final int update(
            Uri uri, ContentValues values, String selection, String[] selectionArgs) {
        throw new UnsupportedOperationException("Update not supported");
    }
}
+6 −0
Original line number Diff line number Diff line
@@ -2400,6 +2400,12 @@
        android:permissionGroup="android.permission-group.SYSTEM_TOOLS"
        android:protectionLevel="signature" />

    <!-- Internal permission to allows an application to read indexable data.
        @hide -->
    <permission android:name="android.permission.READ_SEARCH_INDEXABLES"
        android:permissionGroup="android.permission-group.SYSTEM_TOOLS"
        android:protectionLevel="signature|system" />

    <!-- Allows applications to set a live wallpaper.
         @hide XXX Change to signature once the picker is moved to its
         own apk as Ghod Intended. -->