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

Commit 03b2ea11 authored by satok's avatar satok
Browse files

Support xml configuration file for the spell checker and add the spell checker subtype

Change-Id: I74715855525fc0a1282238d593ad37aefd42bfc3
parent 7d608423
Loading
Loading
Loading
Loading
+15 −0
Original line number Original line Diff line number Diff line
@@ -911,6 +911,8 @@ package android {
    field public static final int stretchMode = 16843030; // 0x1010116
    field public static final int stretchMode = 16843030; // 0x1010116
    field public static final int subtitle = 16843473; // 0x10102d1
    field public static final int subtitle = 16843473; // 0x10102d1
    field public static final int subtitleTextStyle = 16843513; // 0x10102f9
    field public static final int subtitleTextStyle = 16843513; // 0x10102f9
    field public static final int subtypeExtraValue = 16843684; // 0x10103a4
    field public static final int subtypeLocale = 16843683; // 0x10103a3
    field public static final int suggestActionMsg = 16843228; // 0x10101dc
    field public static final int suggestActionMsg = 16843228; // 0x10101dc
    field public static final int suggestActionMsgColumn = 16843229; // 0x10101dd
    field public static final int suggestActionMsgColumn = 16843229; // 0x10101dd
    field public static final int suggestionsEnabled = 16843632; // 0x1010370
    field public static final int suggestionsEnabled = 16843632; // 0x1010370
@@ -24268,6 +24270,9 @@ package android.view.textservice {
    method public android.content.ComponentName getComponent();
    method public android.content.ComponentName getComponent();
    method public java.lang.String getId();
    method public java.lang.String getId();
    method public java.lang.String getPackageName();
    method public java.lang.String getPackageName();
    method public java.lang.String getSettingsActivity();
    method public android.view.textservice.SpellCheckerSubtype getSubtypeAt(int);
    method public int getSubtypeCount();
    method public android.graphics.drawable.Drawable loadIcon(android.content.pm.PackageManager);
    method public android.graphics.drawable.Drawable loadIcon(android.content.pm.PackageManager);
    method public java.lang.CharSequence loadLabel(android.content.pm.PackageManager);
    method public java.lang.CharSequence loadLabel(android.content.pm.PackageManager);
    method public void writeToParcel(android.os.Parcel, int);
    method public void writeToParcel(android.os.Parcel, int);
@@ -24287,6 +24292,16 @@ package android.view.textservice {
    method public abstract void onGetSuggestions(android.view.textservice.SuggestionsInfo[]);
    method public abstract void onGetSuggestions(android.view.textservice.SuggestionsInfo[]);
  }
  }
  public final class SpellCheckerSubtype implements android.os.Parcelable {
    ctor public SpellCheckerSubtype(int, java.lang.String, java.lang.String);
    method public int describeContents();
    method public java.lang.String getExtraValue();
    method public java.lang.String getLocale();
    method public int getNameResId();
    method public void writeToParcel(android.os.Parcel, int);
    field public static final android.os.Parcelable.Creator CREATOR;
  }
  public final class SuggestionsInfo implements android.os.Parcelable {
  public final class SuggestionsInfo implements android.os.Parcelable {
    ctor public SuggestionsInfo(int, java.lang.String[]);
    ctor public SuggestionsInfo(int, java.lang.String[]);
    ctor public SuggestionsInfo(int, java.lang.String[], int, int);
    ctor public SuggestionsInfo(int, java.lang.String[], int, int);
+131 −3
Original line number Original line Diff line number Diff line
@@ -16,30 +16,122 @@


package android.view.textservice;
package android.view.textservice;


import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;

import android.content.ComponentName;
import android.content.ComponentName;
import android.content.Context;
import android.content.Context;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
import android.content.pm.ServiceInfo;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.content.res.XmlResourceParser;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.Drawable;
import android.os.Parcel;
import android.os.Parcel;
import android.os.Parcelable;
import android.os.Parcelable;
import android.util.AttributeSet;
import android.util.Slog;
import android.util.Xml;

import java.io.IOException;
import java.util.ArrayList;


/**
/**
 * This class is used to specify meta information of an spell checker.
 * This class is used to specify meta information of an spell checker.
 */
 */
public final class SpellCheckerInfo implements Parcelable {
public final class SpellCheckerInfo implements Parcelable {
    private static final String TAG = SpellCheckerInfo.class.getSimpleName();
    private final ResolveInfo mService;
    private final ResolveInfo mService;
    private final String mId;
    private final String mId;
    private final int mLabel;

    /**
     * The spell checker setting activity's name, used by the system settings to
     * launch the setting activity.
     */
    private final String mSettingsActivityName;

    /**
     * The array of the subtypes.
     */
    private final ArrayList<SpellCheckerSubtype> mSubtypes = new ArrayList<SpellCheckerSubtype>();


    /**
    /**
     * Constructor.
     * Constructor.
     * @hide
     * @hide
     */
     */
    public SpellCheckerInfo(Context context, ResolveInfo service) {
    public SpellCheckerInfo(Context context, ResolveInfo service)
            throws XmlPullParserException, IOException {
        mService = service;
        mService = service;
        ServiceInfo si = service.serviceInfo;
        ServiceInfo si = service.serviceInfo;
        mId = new ComponentName(si.packageName, si.name).flattenToShortString();
        mId = new ComponentName(si.packageName, si.name).flattenToShortString();

        final PackageManager pm = context.getPackageManager();
        int label = 0;
        String settingsActivityComponent = null;
        int isDefaultResId = 0;

        XmlResourceParser parser = null;
        try {
            parser = si.loadXmlMetaData(pm, SpellCheckerSession.SERVICE_META_DATA);
            if (parser == null) {
                throw new XmlPullParserException("No "
                        + SpellCheckerSession.SERVICE_META_DATA + " meta-data");
            }

            final Resources res = pm.getResourcesForApplication(si.applicationInfo);
            final AttributeSet attrs = Xml.asAttributeSet(parser);
            int type;
            while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
                    && type != XmlPullParser.START_TAG) {
            }

            final String nodeName = parser.getName();
            if (!"spell-checker".equals(nodeName)) {
                throw new XmlPullParserException(
                        "Meta-data does not start with spell-checker tag");
            }

            TypedArray sa = res.obtainAttributes(attrs,
                    com.android.internal.R.styleable.SpellChecker);
            label = sa.getResourceId(com.android.internal.R.styleable.SpellChecker_label, 0);
            settingsActivityComponent = sa.getString(
                    com.android.internal.R.styleable.SpellChecker_settingsActivity);
            sa.recycle();

            final int depth = parser.getDepth();
            // Parse all subtypes
            while (((type = parser.next()) != XmlPullParser.END_TAG || parser.getDepth() > depth)
                    && type != XmlPullParser.END_DOCUMENT) {
                if (type == XmlPullParser.START_TAG) {
                    final String subtypeNodeName = parser.getName();
                    if (!"subtype".equals(subtypeNodeName)) {
                        throw new XmlPullParserException(
                                "Meta-data in spell-checker does not start with subtype tag");
                    }
                    final TypedArray a = res.obtainAttributes(
                            attrs, com.android.internal.R.styleable.SpellChecker_Subtype);
                    SpellCheckerSubtype subtype = new SpellCheckerSubtype(
                            a.getResourceId(com.android.internal.R.styleable
                                    .SpellChecker_Subtype_label, 0),
                            a.getString(com.android.internal.R.styleable
                                    .SpellChecker_Subtype_subtypeLocale),
                            a.getString(com.android.internal.R.styleable
                                    .SpellChecker_Subtype_subtypeExtraValue));
                    mSubtypes.add(subtype);
                }
            }
        } catch (Exception e) {
            Slog.e(TAG, "Caught exception: " + e);
            throw new XmlPullParserException(
                    "Unable to create context for: " + si.packageName);
        } finally {
            if (parser != null) parser.close();
        }
        mLabel = label;
        mSettingsActivityName = settingsActivityComponent;
    }
    }


    /**
    /**
@@ -47,8 +139,11 @@ public final class SpellCheckerInfo implements Parcelable {
     * @hide
     * @hide
     */
     */
    public SpellCheckerInfo(Parcel source) {
    public SpellCheckerInfo(Parcel source) {
        mLabel = source.readInt();
        mId = source.readString();
        mId = source.readString();
        mSettingsActivityName = source.readString();
        mService = ResolveInfo.CREATOR.createFromParcel(source);
        mService = ResolveInfo.CREATOR.createFromParcel(source);
        source.readTypedList(mSubtypes, SpellCheckerSubtype.CREATOR);
    }
    }


    /**
    /**
@@ -69,7 +164,7 @@ public final class SpellCheckerInfo implements Parcelable {
    }
    }


    /**
    /**
     * Return the .apk package that implements this input method.
     * Return the .apk package that implements this.
     */
     */
    public String getPackageName() {
    public String getPackageName() {
        return mService.serviceInfo.packageName;
        return mService.serviceInfo.packageName;
@@ -83,8 +178,11 @@ public final class SpellCheckerInfo implements Parcelable {
     */
     */
    @Override
    @Override
    public void writeToParcel(Parcel dest, int flags) {
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeInt(mLabel);
        dest.writeString(mId);
        dest.writeString(mId);
        dest.writeString(mSettingsActivityName);
        mService.writeToParcel(dest, flags);
        mService.writeToParcel(dest, flags);
        dest.writeTypedList(mSubtypes);
    }
    }




@@ -110,7 +208,8 @@ public final class SpellCheckerInfo implements Parcelable {
     * @param pm Supply a PackageManager used to load the spell checker's resources.
     * @param pm Supply a PackageManager used to load the spell checker's resources.
     */
     */
    public CharSequence loadLabel(PackageManager pm) {
    public CharSequence loadLabel(PackageManager pm) {
        return mService.loadLabel(pm);
        if (mLabel == 0 || pm == null) return "";
        return pm.getText(getPackageName(), mLabel, mService.serviceInfo.applicationInfo);
    }
    }


    /**
    /**
@@ -122,6 +221,35 @@ public final class SpellCheckerInfo implements Parcelable {
        return mService.loadIcon(pm);
        return mService.loadIcon(pm);
    }
    }


    /**
     * Return the class name of an activity that provides a settings UI.
     * You can launch this activity be starting it with
     * an {@link android.content.Intent} whose action is MAIN and with an
     * explicit {@link android.content.ComponentName}
     * composed of {@link #getPackageName} and the class name returned here.
     *
     * <p>A null will be returned if there is no settings activity.
     */
    public String getSettingsActivity() {
        return mSettingsActivityName;
    }

    /**
     * Return the count of the subtypes.
     */
    public int getSubtypeCount() {
        return mSubtypes.size();
    }

    /**
     * Return the subtype at the specified index.
     *
     * @param index the index of the subtype to return.
     */
    public SpellCheckerSubtype getSubtypeAt(int index) {
        return mSubtypes.get(index);
    }

    /**
    /**
     * Used to make this class parcelable.
     * Used to make this class parcelable.
     */
     */
+19 −0
Original line number Original line Diff line number Diff line
/*
 * Copyright (C) 2011 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.view.textservice;

parcelable SpellCheckerSubtype;
+159 −0
Original line number Original line Diff line number Diff line
/*
 * Copyright (C) 2011 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.view.textservice;

import android.content.Context;
import android.os.Parcel;
import android.os.Parcelable;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;

/**
 * This class is used to specify meta information of a subtype contained in a spell checker.
 * Subtype can describe locale (e.g. en_US, fr_FR...) used for settings.
 */
public final class SpellCheckerSubtype implements Parcelable {

    private final int mSubtypeHashCode;
    private final int mSubtypeNameResId;
    private final String mSubtypeLocale;
    private final String mSubtypeExtraValue;

    /**
     * Constructor
     * @param nameId The name of the subtype
     * @param locale The locale supported by the subtype
     * @param extraValue The extra value of the subtype
     */
    public SpellCheckerSubtype(int nameId, String locale, String extraValue) {
        mSubtypeNameResId = nameId;
        mSubtypeLocale = locale != null ? locale : "";
        mSubtypeExtraValue = extraValue != null ? extraValue : "";
        mSubtypeHashCode = hashCodeInternal(mSubtypeLocale, mSubtypeExtraValue);
    }

    SpellCheckerSubtype(Parcel source) {
        String s;
        mSubtypeNameResId = source.readInt();
        s = source.readString();
        mSubtypeLocale = s != null ? s : "";
        s = source.readString();
        mSubtypeExtraValue = s != null ? s : "";
        mSubtypeHashCode = hashCodeInternal(mSubtypeLocale, mSubtypeExtraValue);
    }

    /**
     * @return the name of the subtype
     */
    public int getNameResId() {
        return mSubtypeNameResId;
    }

    /**
     * @return the locale of the subtype
     */
    public String getLocale() {
        return mSubtypeLocale;
    }

    /**
     * @return the extra value of the subtype
     */
    public String getExtraValue() {
        return mSubtypeExtraValue;
    }

    @Override
    public int hashCode() {
        return mSubtypeHashCode;
    }

    @Override
    public boolean equals(Object o) {
        if (o instanceof SpellCheckerSubtype) {
            SpellCheckerSubtype subtype = (SpellCheckerSubtype) o;
            return (subtype.hashCode() == hashCode())
                && (subtype.getNameResId() == getNameResId())
                && (subtype.getLocale().equals(getLocale()))
                && (subtype.getExtraValue().equals(getExtraValue()));
        }
        return false;
    }

    @Override
    public int describeContents() {
        return 0;
    }

    @Override
    public void writeToParcel(Parcel dest, int parcelableFlags) {
        dest.writeInt(mSubtypeNameResId);
        dest.writeString(mSubtypeLocale);
        dest.writeString(mSubtypeExtraValue);
    }

    public static final Parcelable.Creator<SpellCheckerSubtype> CREATOR
            = new Parcelable.Creator<SpellCheckerSubtype>() {
        @Override
        public SpellCheckerSubtype createFromParcel(Parcel source) {
            return new SpellCheckerSubtype(source);
        }

        @Override
        public SpellCheckerSubtype[] newArray(int size) {
            return new SpellCheckerSubtype[size];
        }
    };

    private static int hashCodeInternal(String locale, String extraValue) {
        return Arrays.hashCode(new Object[] {locale, extraValue});
    }

    /**
     * Sort the list of subtypes
     * @param context Context will be used for getting localized strings
     * @param flags Flags for the sort order
     * @param sci SpellCheckerInfo of which subtypes are subject to be sorted
     * @param subtypeList List which will be sorted
     * @return Sorted list of subtypes
     * @hide
     */
    public static List<SpellCheckerSubtype> sort(Context context, int flags, SpellCheckerInfo sci,
            List<SpellCheckerSubtype> subtypeList) {
        if (sci == null) return subtypeList;
        final HashSet<SpellCheckerSubtype> subtypesSet = new HashSet<SpellCheckerSubtype>(
                subtypeList);
        final ArrayList<SpellCheckerSubtype> sortedList = new ArrayList<SpellCheckerSubtype>();
        int N = sci.getSubtypeCount();
        for (int i = 0; i < N; ++i) {
            SpellCheckerSubtype subtype = sci.getSubtypeAt(i);
            if (subtypesSet.contains(subtype)) {
                sortedList.add(subtype);
                subtypesSet.remove(subtype);
            }
        }
        // If subtypes in subtypesSet remain, that means these subtypes are not
        // contained in sci, so the remaining subtypes will be appended.
        for (SpellCheckerSubtype subtype: subtypesSet) {
            sortedList.add(subtype);
        }
        return sortedList;
    }
}
+28 −0
Original line number Original line Diff line number Diff line
@@ -2224,6 +2224,34 @@
        <attr name="imeSubtypeExtraValue" format="string" />
        <attr name="imeSubtypeExtraValue" format="string" />
    </declare-styleable>
    </declare-styleable>


    <!-- Use <code>spell-checker</code> as the root tag of the XML resource that
         describes an
         {@link android.service.textservice.SpellCheckerService} service, which is
         referenced from its
         {@link android.view.textservice.SpellCheckerSession#SERVICE_META_DATA}
         meta-data entry.  Described here are the attributes that can be
         included in that tag. -->
    <declare-styleable name="SpellChecker">
        <!-- The name of the spell checker. -->
        <attr name="label" />
        <!-- Component name of an activity that allows the user to modify
             the settings for this service. -->
        <attr name="settingsActivity"/>
    </declare-styleable>

    <!-- This is the subtype of the spell checker. Subtype can describe locales (e.g. en_US, fr_FR...) -->
    <declare-styleable name="SpellChecker_Subtype">
        <!-- The name of the subtype. -->
        <attr name="label" />
        <!-- The locale of the subtype. This string should be a locale (e.g. en_US, fr_FR...)
             This is also used by the framework to know the supported locales
             of the spell checker.  -->
        <attr name="subtypeLocale" format="string" />
        <!-- The extra value of the subtype. This string can be any string and will be passed to
             the SpellChecker.  -->
        <attr name="subtypeExtraValue" format="string" />
    </declare-styleable>

    <!-- Use <code>accessibility-service</code> as the root tag of the XML resource that
    <!-- Use <code>accessibility-service</code> as the root tag of the XML resource that
         describes an {@link android.accessibilityservice.AccessibilityService} service,
         describes an {@link android.accessibilityservice.AccessibilityService} service,
         which is referenced from its
         which is referenced from its
Loading